Condividi tramite


Come sintetizzare la voce dal testo

Documentazione di riferimento | Pacchetto (NuGet) | Ulteriori esempi in GitHub

In questa guida pratica vengono illustrati i modelli di progettazione comuni per eseguire la sintesi vocale.

Per altre informazioni sulle aree seguenti, vedere Che cos'è la sintesi vocale?

  • Recupero di risposte come flussi in memoria.
  • Personalizzazione della frequenza di campionamento e della velocità in bit dell'output.
  • Invio di richieste di sintesi tramite Speech Synthesis Markup Language (SSML).
  • Uso di voci neurali.
  • Sottoscrizione di eventi e azioni sui risultati.

Selezionare il linguaggio di sintesi e la voce

La funzionalità sintesi vocale nel servizio Voce supporta più di 400 voci e più di 140 lingue e varianti. È possibile ottenere l'elenco completo o provarle nella Raccolta voci.

Specificare la lingua o la voce di SpeechConfig perché corrispondano al testo di input e usino la voce specificata. Il seguente frammento di codice illustra il funzionamento di questa tecnica:

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

Tutte le voci neurali sono multilingue e parlano fluentemente sia la propria lingua che l’inglese. Ad esempio, se il testo di input in inglese è "I'm excited to try text to speech" e si imposta es-ES-ElviraNeural, il testo viene pronunciato in inglese con un accento spagnolo.

Se la voce non parla la lingua del testo di input, il servizio cognitivo di Azure per la voce non creerà audio sintetizzato. Per un elenco completo delle voci neurali supportate, consultare Lingue e voci supportate per il servizio cognitivo di Azure per la voce.

Nota

La voce predefinita è la prima voce restituita per impostazioni locali dall'API dell'elenco voci.

La voce che parla viene determinata in ordine di priorità come indicato di seguito:

  • Se non si imposta SpeechSynthesisVoiceName o SpeechSynthesisLanguage, a parlare sarà la voce predefinita per en-US.
  • Se si imposta solo SpeechSynthesisLanguage, a parlare sarà la voce predefinita per impostazioni locali specificate.
  • Se SpeechSynthesisVoiceName e SpeechSynthesisLanguage sono entrambi impostati, l'impostazione SpeechSynthesisLanguage verrà ignorata. La voce specificata tramite SpeechSynthesisVoiceName sarà quella a parlare.
  • Se l'elemento voce viene impostato tramite Speech Synthesis Markup Language (SSML), le impostazioni SpeechSynthesisVoiceName e SpeechSynthesisLanguage verranno ignorate.

In sintesi, l'ordine di priorità può essere descritto come segue:

SpeechSynthesisVoiceName SpeechSynthesisLanguage SSML Risultato
La voce predefinita per en-US sarà quella a parlare
La voce predefinita per le impostazioni locali specificate sarà quella a parlare.
La voce specificata tramite SpeechSynthesisVoiceName sarà quella a parlare.
La voce specificata tramite SSML sarà quella a parlare.

Sintetizzare la voce in un file

Creare un oggetto SpeechSynthesizer. Questo oggetto, mostrato nei seguenti frammenti di codice, esegue le conversioni di sintesi vocale e invia l’output ad altoparlanti, file o altri flussi di output. SpeechSynthesizer accetta come parametri:

  • L’oggetto SpeechConfig creato nel passaggio precedente
  • Un oggetto AudioConfig che specifica la modalità di gestione dei risultati di output
  1. Creare un'istanza AudioConfig per scrivere automaticamente l'output in un file .wav usando la funzione FromWavFileOutput(): Creare un'istanza con un'istruzione using.

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

    Un'istruzione using in questo contesto elimina automaticamente le risorse non gestite e fa in modo che l'oggetto esca dall'ambito dopo l'eliminazione.

  2. Creare un'istanza di SpeechSynthesizer con un'altra istruzione using. Passare l'oggetto speechConfig e l'oggetto audioConfig come parametri. Per sintetizzare il parlato e scrivere in un file, eseguire SpeakTextAsync() con una stringa di testo.

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

Quando si esegue il programma, viene creato un file sintetizzato .wav, scritto nel percorso specificato. Questo risultato è un buon esempio dell'utilizzo più semplice. Si esamini quindi la personalizzazione dell'output e la gestione della risposta di output come flusso in memoria per l'uso di scenari personalizzati.

Sintetizzare l'output dell'altoparlante

Per eseguire l'output vocale sintetizzato nel dispositivo di output attivo corrente, ad esempio un altoparlante, omettere il parametro AudioConfig durante la creazione dell'istanza SpeechSynthesizer. Ecco un esempio:

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

Ottenere un risultato come flusso in memoria

È possibile usare i dati audio risultanti come flusso in memoria anziché scrivere direttamente in un file. Con il flusso in memoria è possibile creare un comportamento personalizzato:

  • Astrarre la matrice di byte risultante come flusso ricercabile per i servizi downstream personalizzati.
  • Integrare il risultato con altri servizi o API.
  • Modificare i dati audio, scrivere intestazioni di .wav personalizzate ed eseguire attività correlate.

È possibile apportare questa modifica all'esempio precedente. Prima rimuovere il blocco AudioConfig, poiché da questo punto in poi il comportamento di output viene gestito manualmente per un maggior controllo. Passare null per AudioConfig nel costruttore SpeechSynthesizer.

Nota

Se si passa null per AudioConfig, invece di ometterlo come nel precedente esempio di output nell'altoparlante, l'audio non viene riprodotto per impostazione predefinita nel dispositivo di output attivo corrente.

Salvare il risultato in una variabile SpeechSynthesisResult. La proprietà AudioData contiene un'istanza byte [] per i dati di output. Questo oggetto byte [] può essere gestito manualmente oppure è possibile usare la classe AudioDataStream per gestire il flusso in memoria.

In questo esempio si usa la funzione statica AudioDataStream.FromResult() per ottenere un flusso dal risultato:

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

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

A questo punto, è possibile implementare qualsiasi comportamento personalizzato usando l'oggetto stream risultante.

Personalizzare il formato audio

È possibile personalizzare gli attributi di output audio, tra cui:

  • Tipo di file audio
  • Frequenza di campionamento
  • Profondità di bit

Per cambiare il formato audio, usare la funzione SetSpeechSynthesisOutputFormat() nell'oggetto SpeechConfig. Questa funzione prevede un'istanza di enum di tipo SpeechSynthesisOutputFormat. Usare il enum per selezionare il formato di output. Per i formati disponili, vedere l’elenco dei formati audio.

Sono disponibili varie opzioni per tipi di file diversi a seconda dei requisiti. Per definizione, i formati non elaborati come Raw24Khz16BitMonoPcm non includono intestazioni audio. Usare i formati non elaborati solo in una di queste situazioni:

  • Si sa che l'implementazione downstream può decodificare un flusso di bit non elaborato.
  • Si prevede di compilare manualmente le intestazioni in base a fattori quali profondità bit, frequenza di campionamento e numero di canali.

Questo esempio specifica un formato RIFF ad alta fedeltà Riff24Khz16BitMonoPcm impostando SpeechSynthesisOutputFormat nell'oggetto SpeechConfig. Analogamente all'esempio della sezione precedente, è possibile usare AudioDataStream per ottenere un flusso in memoria del risultato e quindi scriverlo in un file.

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

Quando si esegue il programma, scrive un file .wav nel percorso specificato.

Usare SSML per personalizzare le caratteristiche vocali

È possibile usare SSML per ottimizzare il tono, la pronuncia, la velocità del parlato, il volume e altri aspetti nell'output della sintesi vocale inviando le richieste da uno schema XML. Questa sezione illustra un esempio di modifica della voce. Per altre informazioni, vedere Panoramica di Speech Synthesis Markup Language.

Per iniziare a usare SSML per la personalizzazione, è necessario apportare una piccola modifica che cambia la voce.

  1. Creare prima di tutto un nuovo file XML per la configurazione di SSML nella directory radice del progetto.

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

    In questo esempio, file è ssml.xml. L'elemento radice è sempre <speak>. Il wrapping del testo in un elemento <voice> consente di modificare la voce usando il parametro name. Per l'elenco completo delle voci neurali supportate, vedere Supporto linguistico.

  2. Cambiare la richiesta di sintesi vocale in modo che faccia riferimento al file XML. La richiesta è essenzialmente la stessa, ma invece di usare la funzione SpeakTextAsync() si usa SpeakSsmlAsync(). Questa funzione prevede una stringa XML. Prima di tutto, caricare la configurazione di SSML come stringa usando File.ReadAllText(). Da qui, l'oggetto risultato è esattamente lo stesso degli esempi precedenti.

    Nota

    Se si usa Visual Studio, la configurazione di compilazione probabilmente non troverà il file XML per impostazione predefinita. Fare clic con il pulsante destro del mouse sul file XML e selezionare Proprietà. Impostare Azione di compilazione su Contenuto Impostare Copia nella directory di output su Copia sempre.

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

Nota

Per modificare la voce senza usare SSML, è possibile impostare la proprietà su SpeechConfig tramite SpeechConfig.SpeechSynthesisVoiceName = "en-US-AvaMultilingualNeural";.

Sottoscrivere eventi di sintetizzatore

È possibile ottenere altre informazioni dettagliate sull'elaborazione del testo e sui risultati del riconoscimento vocale. Ad esempio, è possibile sapere quando il sintetizzatore inizia e si arresta oppure si potrebbe voler conoscere altri eventi rilevati durante la sintesi.

Quando si usa SpeechSynthesizer per la sintesi vocale, è possibile sottoscrivere gli eventi in questa tabella:

Event Descrizione Caso d'uso
BookmarkReached Segnala che è stato raggiunto un segnalibro. Per attivare un evento raggiunto da un segnalibro, è necessario un elemento bookmark nel SSML. Questo evento segnala il tempo trascorso dell'audio di output tra l'inizio della sintesi e l'elemento bookmark. La proprietà dell'evento Text è il valore stringa impostato nell'attributo mark del segnalibro. Gli elementi bookmark non vengono pronunciati. È possibile usare l'elemento bookmark per inserire marcatori personalizzati in SSML per ottenere l'offset di ogni marcatore nel flusso audio. L'elemento bookmark può essere usato per fare riferimento a una posizione specifica nella sequenza di testo o tag.
SynthesisCanceled Segnala che la sintesi vocale è stata annullata. È possibile confermare quando la sintesi è annullata.
SynthesisCompleted Segnala che la sintesi vocale è stata completata. È possibile confermare quando la sintesi è stata completata.
SynthesisStarted Segnala che la sintesi vocale è stata completata. È possibile confermare l'avvio della sintesi.
Synthesizing Segnala che la sintesi vocale è in corso. Questo evento viene generato ogni volta che l'SDK riceve un blocco audio dal servizio Voce. È possibile confermare quando la sintesi è in corso.
VisemeReceived Segnala che è stato ricevuto un evento visema. I Visemi vengono spesso usati per rappresentare le posizioni chiave nel parlato osservato. Le pose chiave includono la posizione delle labbra, della mascella e della lingua nella produzione di un particolare fonema. È possibile usare visemi per animare il viso di un personaggio durante la riproduzione dell'audio vocale.
WordBoundary Segnala che è stato ricevuto un limite di parola. Questo evento viene generato all'inizio di ogni nuova parola pronunciata, punteggiatura e frase. L'evento segnala l'offset di tempo della parola corrente, in tick, dall'inizio dell'audio di output. Questo evento segnala anche la posizione del carattere nel testo di input o SSML immediatamente prima della parola che sta per essere pronunciata. Questo evento viene comunemente usato per ottenere posizioni relative del testo e dell'audio corrispondente. Potrebbe essere necessario conoscere una nuova parola e quindi intervenire in base alla tempistica. Ad esempio, è possibile ottenere informazioni che consentono di decidere quando e per quanto tempo evidenziare le parole quando vengono pronunciate.

Nota

Gli eventi vengono generati man mano che i dati audio di output diventano disponibili, che è più veloce della riproduzione in un dispositivo di output. Il chiamante deve sincronizzare in modo appropriato lo streaming e il tempo reale.

Ecco un esempio che illustra come sottoscrivere eventi per la sintesi vocale.

Importante

Se si usa una chiave API, archiviarla in modo sicuro in un'altra posizione, ad esempio in Azure Key Vault. Non includere la chiave API direttamente nel codice e non esporla mai pubblicamente.

Per altre informazioni sulla sicurezza dei servizi di intelligenza artificiale, vedere Autenticare le richieste a Servizi di Azure AI.

È possibile seguire le istruzioni nella guida introduttiva, ma sostituire il contenuto del file Program.cs con il codice C# seguente:

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

È possibile trovare altri esempi di testo per il riconoscimento vocale in GitHub.

Usare un endpoint personalizzato

Dal punto di vista funzionale, l'endpoint personalizzato è identico all'endpoint standard usato per le richieste di sintesi vocale.

Una differenza è che EndpointId deve essere specificato per usare la voce personalizzata tramite Speech SDK. È possibile iniziare con l‘avvio rapido della sintesi vocale e quindi aggiornare il codice con EndpointId e SpeechSynthesisVoiceName.

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

Per usare una voce personalizzata tramite Speech Synthesis Markup Language (SSML), specificare il nome del modello come nome della voce. Questo esempio usa la voce 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>

Eseguire e usare un contenitore

I contenitori del servizio Voce forniscono API di endpoint di query basate su WebSocket a cui si accede tramite Speech SDK e l'interfaccia della riga di comando di Voce. Per impostazione predefinita, l'SDK e l'interfaccia della riga di comando di Voce usano il servizio Voce pubblico. Per usare il contenitore, è necessario modificare il metodo di inizializzazione. Usare un URL host del contenitore invece di chiave e area.

Per altre informazioni sui contenitori, vedere Installare ed eseguire contenitori di Voce con Docker.

Documentazione di riferimento | Pacchetto (NuGet) | Ulteriori esempi in GitHub

In questa guida pratica vengono illustrati i modelli di progettazione comuni per eseguire la sintesi vocale.

Per altre informazioni sulle aree seguenti, vedere Che cos'è la sintesi vocale?

  • Recupero di risposte come flussi in memoria.
  • Personalizzazione della frequenza di campionamento e della velocità in bit dell'output.
  • Invio di richieste di sintesi tramite Speech Synthesis Markup Language (SSML).
  • Uso di voci neurali.
  • Sottoscrizione di eventi e azioni sui risultati.

Selezionare il linguaggio di sintesi e la voce

La funzionalità sintesi vocale nel servizio Voce supporta più di 400 voci e più di 140 lingue e varianti. Fare riferimento all'elenco completo delle impostazioni locali di riconoscimento vocale supportate o provarle in Raccolta voci.

Specificare la lingua o la voce della classe SpeechConfig perché corrispondano al testo di input e usino la voce specificata. Il seguente frammento di codice illustra il funzionamento di questa tecnica:

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

Tutte le voci neurali sono multilingue e parlano fluentemente sia la propria lingua che l’inglese. Ad esempio, se il testo di input in inglese è "I'm excited to try text to speech" e si imposta es-ES-ElviraNeural, il testo viene pronunciato in inglese con un accento spagnolo.

Se la voce non parla la lingua del testo di input, il servizio cognitivo di Azure per la voce non creerà audio sintetizzato. Per un elenco completo delle voci neurali supportate, consultare Lingue e voci supportate per il servizio cognitivo di Azure per la voce.

Nota

La voce predefinita è la prima voce restituita per impostazioni locali dall'API dell'elenco voci.

La voce che parla viene determinata in ordine di priorità come indicato di seguito:

  • Se non si imposta SpeechSynthesisVoiceName o SpeechSynthesisLanguage, a parlare sarà la voce predefinita per en-US.
  • Se si imposta solo SpeechSynthesisLanguage, a parlare sarà la voce predefinita per impostazioni locali specificate.
  • Se SpeechSynthesisVoiceName e SpeechSynthesisLanguage sono entrambi impostati, l'impostazione SpeechSynthesisLanguage verrà ignorata. La voce specificata tramite SpeechSynthesisVoiceName sarà quella a parlare.
  • Se l'elemento voce viene impostato tramite Speech Synthesis Markup Language (SSML), le impostazioni SpeechSynthesisVoiceName e SpeechSynthesisLanguage verranno ignorate.

In sintesi, l'ordine di priorità può essere descritto come segue:

SpeechSynthesisVoiceName SpeechSynthesisLanguage SSML Risultato
La voce predefinita per en-US sarà quella a parlare
La voce predefinita per le impostazioni locali specificate sarà quella a parlare.
La voce specificata tramite SpeechSynthesisVoiceName sarà quella a parlare.
La voce specificata tramite SSML sarà quella a parlare.

Sintetizzare la voce in un file

Creare un oggetto SpeechSynthesizer. Questo oggetto, mostrato nei seguenti frammenti di codice, esegue le conversioni di sintesi vocale e invia l’output ad altoparlanti, file o altri flussi di output. SpeechSynthesizer accetta come parametri:

  • L’oggetto SpeechConfig creato nel passaggio precedente
  • Un oggetto AudioConfig che specifica la modalità di gestione dei risultati di output
  1. Creare un'istanza AudioConfig per scrivere automaticamente l'output in un file .wav usando la funzione FromWavFileOutput():

    void synthesizeSpeech()
    {
        auto speechConfig = SpeechConfig::FromSubscription("YourSpeechKey", "YourSpeechRegion");
        auto audioConfig = AudioConfig::FromWavFileOutput("path/to/write/file.wav");
    }
    
  2. Creare un'istanza di SpeechSynthesizer. Passare l'oggetto speechConfig e l'oggetto audioConfig come parametri. Per sintetizzare il parlato e scrivere in un file, eseguire SpeakTextAsync() con una stringa di testo.

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

Quando si esegue il programma, viene creato un file sintetizzato .wav, scritto nel percorso specificato. Questo risultato è un buon esempio dell'utilizzo più semplice. Si esamini quindi la personalizzazione dell'output e la gestione della risposta di output come flusso in memoria per l'uso di scenari personalizzati.

Sintetizzare l'output dell'altoparlante

Per eseguire l'output vocale sintetizzato nel dispositivo di output attivo corrente, ad esempio un altoparlante, omettere il parametro AudioConfig durante la creazione dell'istanza SpeechSynthesizer. Ecco un esempio:

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

Ottenere un risultato come flusso in memoria

È possibile usare i dati audio risultanti come flusso in memoria anziché scrivere direttamente in un file. Con il flusso in memoria è possibile creare un comportamento personalizzato:

  • Astrarre la matrice di byte risultante come flusso ricercabile per i servizi downstream personalizzati.
  • Integrare il risultato con altri servizi o API.
  • Modificare i dati audio, scrivere intestazioni di .wav personalizzate ed eseguire attività correlate.

È possibile apportare questa modifica all'esempio precedente. Prima rimuovere il blocco AudioConfig, poiché da questo punto in poi il comportamento di output viene gestito manualmente per un maggior controllo. Passare NULL per AudioConfig nel costruttore SpeechSynthesizer.

Nota

Se si passa NULL per AudioConfig, invece di ometterlo come nel precedente esempio di output nell'altoparlante, l'audio non viene riprodotto per impostazione predefinita nel dispositivo di output attivo corrente.

Salvare il risultato in una variabile SpeechSynthesisResult. Il getter GetAudioData restituisce un'istanza byte [] per i dati di output. Questo oggetto byte [] può essere gestito manualmente oppure è possibile usare la classe AudioDataStream per gestire il flusso in memoria.

In questo esempio si usa la funzione statica AudioDataStream.FromResult() per ottenere un flusso dal risultato.

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

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

A questo punto, è possibile implementare qualsiasi comportamento personalizzato usando l'oggetto stream risultante.

Personalizzare il formato audio

È possibile personalizzare gli attributi di output audio, tra cui:

  • Tipo di file audio
  • Frequenza di campionamento
  • Profondità di bit

Per cambiare il formato audio, usare la funzione SetSpeechSynthesisOutputFormat() nell'oggetto SpeechConfig. Questa funzione prevede un'istanza di enum di tipo SpeechSynthesisOutputFormat. Usare il enum per selezionare il formato di output. Per i formati disponili, vedere l’elenco dei formati audio.

Sono disponibili varie opzioni per tipi di file diversi a seconda dei requisiti. Per definizione, i formati non elaborati come Raw24Khz16BitMonoPcm non includono intestazioni audio. Usare i formati non elaborati solo in una di queste situazioni:

  • Si sa che l'implementazione downstream può decodificare un flusso di bit non elaborato.
  • Si prevede di compilare manualmente le intestazioni in base a fattori quali profondità bit, frequenza di campionamento e numero di canali.

Questo esempio specifica un formato RIFF ad alta fedeltà Riff24Khz16BitMonoPcm impostando SpeechSynthesisOutputFormat nell'oggetto SpeechConfig. Analogamente all'esempio della sezione precedente, è possibile usare AudioDataStream per ottenere un flusso in memoria del risultato e quindi scriverlo in un file.

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

Quando si esegue il programma, scrive un file .wav nel percorso specificato.

Usare SSML per personalizzare le caratteristiche vocali

È possibile usare SSML per ottimizzare il tono, la pronuncia, la velocità del parlato, il volume e altri aspetti nell'output della sintesi vocale inviando le richieste da uno schema XML. Questa sezione illustra un esempio di modifica della voce. Per altre informazioni, vedere Panoramica di Speech Synthesis Markup Language.

Per iniziare a usare SSML per la personalizzazione, è necessario apportare una piccola modifica che cambia la voce.

  1. Creare prima di tutto un nuovo file XML per la configurazione di SSML nella directory radice del progetto.

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

    In questo esempio, file è ssml.xml. L'elemento radice è sempre <speak>. Il wrapping del testo in un elemento <voice> consente di modificare la voce usando il parametro name. Per l'elenco completo delle voci neurali supportate, vedere Supporto linguistico.

  2. Cambiare la richiesta di sintesi vocale in modo che faccia riferimento al file XML. La richiesta è principalmente la stessa. Anziché usare la funzione SpeakTextAsync(), si usa SpeakSsmlAsync(). Questa funzione prevede una stringa XML. Prima di tutto, caricare la configurazione di SSML come stringa. Da qui, l'oggetto risultato è esattamente lo stesso degli esempi precedenti.

    void synthesizeSpeech()
    {
        auto speechConfig = SpeechConfig::FromSubscription("YourSpeechKey", "YourSpeechRegion");
        auto speechSynthesizer = SpeechSynthesizer::FromConfig(speechConfig);
    
        std::ifstream file("./ssml.xml");
        std::string ssml, line;
        while (std::getline(file, line))
        {
            ssml += line;
            ssml.push_back('\n');
        }
        auto result = speechSynthesizer->SpeakSsmlAsync(ssml).get();
    
        auto stream = AudioDataStream::FromResult(result);
        stream->SaveToWavFileAsync("path/to/write/file.wav").get();
    }
    

Nota

Per modificare la voce senza usare SSML, è possibile impostare la proprietà su SpeechConfig tramite SpeechConfig.SetSpeechSynthesisVoiceName("en-US-AndrewMultilingualNeural").

Sottoscrivere eventi di sintetizzatore

È possibile ottenere altre informazioni dettagliate sull'elaborazione del testo e sui risultati del riconoscimento vocale. Ad esempio, è possibile sapere quando il sintetizzatore inizia e si arresta oppure si potrebbe voler conoscere altri eventi rilevati durante la sintesi.

Quando si usa SpeechSynthesizer per la sintesi vocale, è possibile sottoscrivere gli eventi in questa tabella:

Event Descrizione Caso d'uso
BookmarkReached Segnala che è stato raggiunto un segnalibro. Per attivare un evento raggiunto da un segnalibro, è necessario un elemento bookmark nel SSML. Questo evento segnala il tempo trascorso dell'audio di output tra l'inizio della sintesi e l'elemento bookmark. La proprietà dell'evento Text è il valore stringa impostato nell'attributo mark del segnalibro. Gli elementi bookmark non vengono pronunciati. È possibile usare l'elemento bookmark per inserire marcatori personalizzati in SSML per ottenere l'offset di ogni marcatore nel flusso audio. L'elemento bookmark può essere usato per fare riferimento a una posizione specifica nella sequenza di testo o tag.
SynthesisCanceled Segnala che la sintesi vocale è stata annullata. È possibile confermare quando la sintesi è annullata.
SynthesisCompleted Segnala che la sintesi vocale è stata completata. È possibile confermare quando la sintesi è stata completata.
SynthesisStarted Segnala che la sintesi vocale è stata completata. È possibile confermare l'avvio della sintesi.
Synthesizing Segnala che la sintesi vocale è in corso. Questo evento viene generato ogni volta che l'SDK riceve un blocco audio dal servizio Voce. È possibile confermare quando la sintesi è in corso.
VisemeReceived Segnala che è stato ricevuto un evento visema. I Visemi vengono spesso usati per rappresentare le posizioni chiave nel parlato osservato. Le pose chiave includono la posizione delle labbra, della mascella e della lingua nella produzione di un particolare fonema. È possibile usare visemi per animare il viso di un personaggio durante la riproduzione dell'audio vocale.
WordBoundary Segnala che è stato ricevuto un limite di parola. Questo evento viene generato all'inizio di ogni nuova parola pronunciata, punteggiatura e frase. L'evento segnala l'offset di tempo della parola corrente, in tick, dall'inizio dell'audio di output. Questo evento segnala anche la posizione del carattere nel testo di input o SSML immediatamente prima della parola che sta per essere pronunciata. Questo evento viene comunemente usato per ottenere posizioni relative del testo e dell'audio corrispondente. Potrebbe essere necessario conoscere una nuova parola e quindi intervenire in base alla tempistica. Ad esempio, è possibile ottenere informazioni che consentono di decidere quando e per quanto tempo evidenziare le parole quando vengono pronunciate.

Nota

Gli eventi vengono generati man mano che i dati audio di output diventano disponibili, che è più veloce della riproduzione in un dispositivo di output. Il chiamante deve sincronizzare in modo appropriato lo streaming e il tempo reale.

Ecco un esempio che illustra come sottoscrivere eventi per la sintesi vocale.

Importante

Se si usa una chiave API, archiviarla in modo sicuro in un'altra posizione, ad esempio in Azure Key Vault. Non includere la chiave API direttamente nel codice e non esporla mai pubblicamente.

Per altre informazioni sulla sicurezza dei servizi di intelligenza artificiale, vedere Autenticare le richieste a Servizi di Azure AI.

È possibile seguire le istruzioni nella guida introduttiva, ma sostituire il contenuto del file main.cpp con il codice seguente:

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

È possibile trovare altri esempi di testo per il riconoscimento vocale in GitHub.

Usare un endpoint personalizzato

Dal punto di vista funzionale, l'endpoint personalizzato è identico all'endpoint standard usato per le richieste di sintesi vocale.

Una differenza è che EndpointId deve essere specificato per usare la voce personalizzata tramite Speech SDK. È possibile iniziare con l‘avvio rapido della sintesi vocale e quindi aggiornare il codice con EndpointId e SpeechSynthesisVoiceName.

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

Per usare una voce personalizzata tramite Speech Synthesis Markup Language (SSML), specificare il nome del modello come nome della voce. Questo esempio usa la voce 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>

Eseguire e usare un contenitore

I contenitori del servizio Voce forniscono API di endpoint di query basate su WebSocket a cui si accede tramite Speech SDK e l'interfaccia della riga di comando di Voce. Per impostazione predefinita, l'SDK e l'interfaccia della riga di comando di Voce usano il servizio Voce pubblico. Per usare il contenitore, è necessario modificare il metodo di inizializzazione. Usare un URL host del contenitore invece di chiave e area.

Per altre informazioni sui contenitori, vedere Installare ed eseguire contenitori di Voce con Docker.

Documentazione di riferimento | Pacchetto (Go) | Ulteriori esempi in GitHub

In questa guida pratica vengono illustrati i modelli di progettazione comuni per eseguire la sintesi vocale.

Per altre informazioni sulle aree seguenti, vedere Che cos'è la sintesi vocale?

  • Recupero di risposte come flussi in memoria.
  • Personalizzazione della frequenza di campionamento e della velocità in bit dell'output.
  • Invio di richieste di sintesi tramite Speech Synthesis Markup Language (SSML).
  • Uso di voci neurali.
  • Sottoscrizione di eventi e azioni sui risultati.

Prerequisiti

  • Una sottoscrizione di Azure. È possibile crearne uno gratuitamente.
  • Creare una risorsa Voce nel portale di Azure.
  • Ottenere la chiave e l'area della risorsa Voce. Dopo aver distribuito la risorsa Voce, selezionare Vai alla risorsa per visualizzare e gestire le chiavi.

Installare Speech SDK

Prima di poter eseguire qualsiasi operazione, è necessario installare Speech SDK per Go.

Sintesi vocale all’altoparlante

Usare l'esempio di codice seguente per eseguire la sintesi vocale nel dispositivo di output audio predefinito. Sostituire le variabili subscription e region con la chiave vocale e la posizione/area. L'esecuzione dello script pronuncia il testo di input all'altoparlante predefinito.

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

Eseguire i comandi seguenti per creare un file go.mod che si collega ai componenti ospitati in GitHub:

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

Ora compilare ed eseguire il codice:

go build
go run quickstart

Per informazioni dettagliate sulle classi, vedere la documentazione di riferimento SpeechConfig e SpeechSynthesizer.

Sintesi vocale nel flusso in memoria

È possibile usare i dati audio risultanti come flusso in memoria anziché scrivere direttamente in un file. Con il flusso in memoria è possibile creare un comportamento personalizzato:

  • Astrarre la matrice di byte risultante come flusso ricercabile per i servizi downstream personalizzati.
  • Integrare il risultato con altri servizi o API.
  • Modificare i dati audio, scrivere intestazioni di .wav personalizzate ed eseguire attività correlate.

È possibile apportare questa modifica all'esempio precedente. Rimuovere il blocco AudioConfig, poiché da questo punto in poi il comportamento di output viene gestito manualmente per un maggior controllo. Passare quindi nil per AudioConfig nel costruttore SpeechSynthesizer.

Nota

Se si passa nil per AudioConfig, invece di ometterlo come nel precedente esempio di output nell'altoparlante, l'audio non verrà riprodotto per impostazione predefinita nel dispositivo di output attivo corrente.

Salvare il risultato in una variabile SpeechSynthesisResult. La proprietà AudioData restituisce un'istanza []byte per i dati di output. Questo oggetto []byte può essere gestito manualmente oppure è possibile usare la classe AudioDataStream per gestire il flusso in memoria. In questo esempio si usa la funzione statica NewAudioDataStreamFromSpeechSynthesisResult() per ottenere un flusso dal risultato.

Sostituire le variabili subscription e region con la chiave vocale e la posizione/area:

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

Eseguire i comandi seguenti per creare un file go.mod che si collega ai componenti ospitati in GitHub:

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

Ora compilare ed eseguire il codice:

go build
go run quickstart

Per informazioni dettagliate sulle classi, vedere la documentazione di riferimento SpeechConfig e SpeechSynthesizer.

Selezionare il linguaggio di sintesi e la voce

La funzionalità sintesi vocale nel servizio Voce supporta più di 400 voci e più di 140 lingue e varianti. È possibile ottenere l'elenco completo o provarle nella Raccolta voci.

Specificare la lingua o la voce di SpeechConfig perché corrispondano al testo di input e usino la voce specificata:

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

Tutte le voci neurali sono multilingue e parlano fluentemente sia la propria lingua che l’inglese. Ad esempio, se il testo di input in inglese è "I'm excited to try text to speech" e si imposta es-ES-ElviraNeural, il testo viene pronunciato in inglese con un accento spagnolo.

Se la voce non parla la lingua del testo di input, il servizio cognitivo di Azure per la voce non creerà audio sintetizzato. Per un elenco completo delle voci neurali supportate, consultare Lingue e voci supportate per il servizio cognitivo di Azure per la voce.

Nota

La voce predefinita è la prima voce restituita per impostazioni locali dall'API dell'elenco voci.

La voce che parla viene determinata in ordine di priorità come indicato di seguito:

  • Se non si imposta SpeechSynthesisVoiceName o SpeechSynthesisLanguage, a parlare sarà la voce predefinita per en-US.
  • Se si imposta solo SpeechSynthesisLanguage, a parlare sarà la voce predefinita per impostazioni locali specificate.
  • Se SpeechSynthesisVoiceName e SpeechSynthesisLanguage sono entrambi impostati, l'impostazione SpeechSynthesisLanguage verrà ignorata. La voce specificata tramite SpeechSynthesisVoiceName sarà quella a parlare.
  • Se l'elemento voce viene impostato tramite Speech Synthesis Markup Language (SSML), le impostazioni SpeechSynthesisVoiceName e SpeechSynthesisLanguage verranno ignorate.

In sintesi, l'ordine di priorità può essere descritto come segue:

SpeechSynthesisVoiceName SpeechSynthesisLanguage SSML Risultato
La voce predefinita per en-US sarà quella a parlare
La voce predefinita per le impostazioni locali specificate sarà quella a parlare.
La voce specificata tramite SpeechSynthesisVoiceName sarà quella a parlare.
La voce specificata tramite SSML sarà quella a parlare.

Usare SSML per personalizzare le caratteristiche vocali

È possibile usare il linguaggio SSML (Speech Synthesis Markup Language) per ottimizzare il tono, la pronuncia, la velocità del parlato, il volume e altro ancora dell'output della sintesi vocale inviando le richieste da XML Schema. Questa sezione illustra un esempio di modifica della voce. Per altre informazioni, vedere Panoramica di Speech Synthesis Markup Language.

Per iniziare a usare SSML per la personalizzazione, è necessario apportare una piccola modifica che cambia la voce.

Creare prima di tutto un nuovo file XML per la configurazione di SSML nella directory radice del progetto. In questo esempio è ssml.xml. L'elemento radice è sempre <speak>. Il wrapping del testo in un elemento <voice> consente di modificare la voce usando il parametro name. Per l'elenco completo delle voci neurali supportate, vedere Supporto linguistico.

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

Successivamente, è necessario cambiare la richiesta di sintesi vocale in modo che faccia riferimento al file XML. La richiesta è essenzialmente la stessa, ma invece di usare la funzione SpeakTextAsync() si usa SpeakSsmlAsync(). Questa funzione prevede una stringa XML, quindi è prima di tutto necessario caricare la configurazione di SSML come stringa usando. Da qui, l'oggetto risultato è esattamente lo stesso degli esempi precedenti.

Nota

Per impostare la voce senza usare SSML, è possibile impostare la proprietà su SpeechConfig tramite speechConfig.SetSpeechSynthesisVoiceName("en-US-AvaMultilingualNeural").

Sottoscrivere eventi di sintetizzatore

È possibile ottenere altre informazioni dettagliate sull'elaborazione del testo e sui risultati del riconoscimento vocale. Ad esempio, è possibile sapere quando il sintetizzatore inizia e si arresta oppure si potrebbe voler conoscere altri eventi rilevati durante la sintesi.

Quando si usa SpeechSynthesizer per la sintesi vocale, è possibile sottoscrivere gli eventi in questa tabella:

Event Descrizione Caso d'uso
BookmarkReached Segnala che è stato raggiunto un segnalibro. Per attivare un evento raggiunto da un segnalibro, è necessario un elemento bookmark nel SSML. Questo evento segnala il tempo trascorso dell'audio di output tra l'inizio della sintesi e l'elemento bookmark. La proprietà dell'evento Text è il valore stringa impostato nell'attributo mark del segnalibro. Gli elementi bookmark non vengono pronunciati. È possibile usare l'elemento bookmark per inserire marcatori personalizzati in SSML per ottenere l'offset di ogni marcatore nel flusso audio. L'elemento bookmark può essere usato per fare riferimento a una posizione specifica nella sequenza di testo o tag.
SynthesisCanceled Segnala che la sintesi vocale è stata annullata. È possibile confermare quando la sintesi è annullata.
SynthesisCompleted Segnala che la sintesi vocale è stata completata. È possibile confermare quando la sintesi è stata completata.
SynthesisStarted Segnala che la sintesi vocale è stata completata. È possibile confermare l'avvio della sintesi.
Synthesizing Segnala che la sintesi vocale è in corso. Questo evento viene generato ogni volta che l'SDK riceve un blocco audio dal servizio Voce. È possibile confermare quando la sintesi è in corso.
VisemeReceived Segnala che è stato ricevuto un evento visema. I Visemi vengono spesso usati per rappresentare le posizioni chiave nel parlato osservato. Le pose chiave includono la posizione delle labbra, della mascella e della lingua nella produzione di un particolare fonema. È possibile usare visemi per animare il viso di un personaggio durante la riproduzione dell'audio vocale.
WordBoundary Segnala che è stato ricevuto un limite di parola. Questo evento viene generato all'inizio di ogni nuova parola pronunciata, punteggiatura e frase. L'evento segnala l'offset di tempo della parola corrente, in tick, dall'inizio dell'audio di output. Questo evento segnala anche la posizione del carattere nel testo di input o SSML immediatamente prima della parola che sta per essere pronunciata. Questo evento viene comunemente usato per ottenere posizioni relative del testo e dell'audio corrispondente. Potrebbe essere necessario conoscere una nuova parola e quindi intervenire in base alla tempistica. Ad esempio, è possibile ottenere informazioni che consentono di decidere quando e per quanto tempo evidenziare le parole quando vengono pronunciate.

Nota

Gli eventi vengono generati man mano che i dati audio di output diventano disponibili, che è più veloce della riproduzione in un dispositivo di output. Il chiamante deve sincronizzare in modo appropriato lo streaming e il tempo reale.

Ecco un esempio che illustra come sottoscrivere eventi per la sintesi vocale.

Importante

Se si usa una chiave API, archiviarla in modo sicuro in un'altra posizione, ad esempio in Azure Key Vault. Non includere la chiave API direttamente nel codice e non esporla mai pubblicamente.

Per altre informazioni sulla sicurezza dei servizi di intelligenza artificiale, vedere Autenticare le richieste a Servizi di Azure AI.

È possibile seguire le istruzioni nella guida introduttiva, ma sostituire il contenuto del file speech-synthesis.go con il codice Go seguente:

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

È possibile trovare altri esempi di testo per il riconoscimento vocale in GitHub.

Eseguire e usare un contenitore

I contenitori del servizio Voce forniscono API di endpoint di query basate su WebSocket a cui si accede tramite Speech SDK e l'interfaccia della riga di comando di Voce. Per impostazione predefinita, l'SDK e l'interfaccia della riga di comando di Voce usano il servizio Voce pubblico. Per usare il contenitore, è necessario modificare il metodo di inizializzazione. Usare un URL host del contenitore invece di chiave e area.

Per altre informazioni sui contenitori, vedere Installare ed eseguire contenitori di Voce con Docker.

Documentazione di riferimento | Ulteriori esempi in GitHub

In questa guida pratica vengono illustrati i modelli di progettazione comuni per eseguire la sintesi vocale.

Per altre informazioni sulle aree seguenti, vedere Che cos'è la sintesi vocale?

  • Recupero di risposte come flussi in memoria.
  • Personalizzazione della frequenza di campionamento e della velocità in bit dell'output.
  • Invio di richieste di sintesi tramite Speech Synthesis Markup Language (SSML).
  • Uso di voci neurali.
  • Sottoscrizione di eventi e azioni sui risultati.

Selezionare il linguaggio di sintesi e la voce

La funzionalità sintesi vocale nel servizio Voce supporta più di 400 voci e più di 140 lingue e varianti. È possibile ottenere l'elenco completo o provarle nella Raccolta voci.

Specificare la lingua o la voce SpeechConfig perché corrispondano al testo di input e usino la voce specificata. Il seguente frammento di codice illustra il funzionamento di questa tecnica:

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

Tutte le voci neurali sono multilingue e parlano fluentemente sia la propria lingua che l’inglese. Ad esempio, se il testo di input in inglese è "I'm excited to try text to speech" e si imposta es-ES-ElviraNeural, il testo viene pronunciato in inglese con un accento spagnolo.

Se la voce non parla la lingua del testo di input, il servizio cognitivo di Azure per la voce non creerà audio sintetizzato. Per un elenco completo delle voci neurali supportate, consultare Lingue e voci supportate per il servizio cognitivo di Azure per la voce.

Nota

La voce predefinita è la prima voce restituita per impostazioni locali dall'API dell'elenco voci.

La voce che parla viene determinata in ordine di priorità come indicato di seguito:

  • Se non si imposta SpeechSynthesisVoiceName o SpeechSynthesisLanguage, a parlare sarà la voce predefinita per en-US.
  • Se si imposta solo SpeechSynthesisLanguage, a parlare sarà la voce predefinita per impostazioni locali specificate.
  • Se SpeechSynthesisVoiceName e SpeechSynthesisLanguage sono entrambi impostati, l'impostazione SpeechSynthesisLanguage verrà ignorata. La voce specificata tramite SpeechSynthesisVoiceName sarà quella a parlare.
  • Se l'elemento voce viene impostato tramite Speech Synthesis Markup Language (SSML), le impostazioni SpeechSynthesisVoiceName e SpeechSynthesisLanguage verranno ignorate.

In sintesi, l'ordine di priorità può essere descritto come segue:

SpeechSynthesisVoiceName SpeechSynthesisLanguage SSML Risultato
La voce predefinita per en-US sarà quella a parlare
La voce predefinita per le impostazioni locali specificate sarà quella a parlare.
La voce specificata tramite SpeechSynthesisVoiceName sarà quella a parlare.
La voce specificata tramite SSML sarà quella a parlare.

Sintetizzare la voce in un file

Creare un oggetto SpeechSynthesizer. Questo oggetto esegue le conversioni di sintesi vocale e invia l’output ad altoparlanti, file o altri flussi di output. SpeechSynthesizer accetta come parametri:

  • Oggetto SpeechConfig creato nel passaggio precedente.
  • Oggetto AudioConfig che specifica la modalità di gestione dei risultati di output.
  1. Creare un'istanza AudioConfig per scrivere automaticamente l'output in un file .wav usando la funzione statica fromWavFileOutput():

    public static void main(String[] args) {
        SpeechConfig speechConfig = SpeechConfig.fromSubscription("YourSpeechKey", "YourSpeechRegion");
        AudioConfig audioConfig = AudioConfig.fromWavFileOutput("path/to/write/file.wav");
    }
    
  2. Creare un'istanza di SpeechSynthesizer. Passare l'oggetto speechConfig e l'oggetto audioConfig come parametri. Per sintetizzare il parlato e scrivere in un file, eseguire SpeakText() con una stringa di testo.

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

Quando si esegue il programma, viene creato un file sintetizzato .wav, scritto nel percorso specificato. Questo risultato è un buon esempio dell'utilizzo più semplice. Si esamini quindi la personalizzazione dell'output e la gestione della risposta di output come flusso in memoria per l'uso di scenari personalizzati.

Sintetizzare l'output dell'altoparlante

È possibile ottenere altre informazioni dettagliate sull'elaborazione del testo e sui risultati del riconoscimento vocale. Ad esempio, è possibile sapere quando il sintetizzatore inizia e si arresta oppure si potrebbe voler conoscere altri eventi rilevati durante la sintesi.

Per eseguire l'output vocale sintetizzato nel dispositivo di output attivo corrente, ad esempio un altoparlante, creare un'istanza AudioConfig usando la funzione statica fromDefaultSpeakerOutput(). Ecco un esempio:

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

Ottenere un risultato come flusso in memoria

È possibile usare i dati audio risultanti come flusso in memoria anziché scrivere direttamente in un file. Con il flusso in memoria è possibile creare un comportamento personalizzato:

  • Astrarre la matrice di byte risultante come flusso ricercabile per i servizi downstream personalizzati.
  • Integrare il risultato con altri servizi o API.
  • Modificare i dati audio, scrivere intestazioni di .wav personalizzate ed eseguire attività correlate.

È possibile apportare questa modifica all'esempio precedente. Prima rimuovere il blocco AudioConfig, poiché da questo punto in poi il comportamento di output viene gestito manualmente per un maggior controllo. Passare quindi null per AudioConfig nel costruttore SpeechSynthesizer.

Nota

Se si passa null per AudioConfig, invece di ometterlo come nel precedente esempio di output nell'altoparlante, l'audio non viene riprodotto per impostazione predefinita nel dispositivo di output attivo corrente.

Salvare il risultato in una variabile SpeechSynthesisResult. La funzione SpeechSynthesisResult.getAudioData() restituisce un'istanza byte [] dei dati di output. Questo oggetto byte [] può essere gestito manualmente oppure è possibile usare la classe AudioDataStream per gestire il flusso in memoria.

In questo esempio si usa la funzione statica AudioDataStream.fromResult() per ottenere un flusso dal risultato.

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

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

A questo punto, è possibile implementare qualsiasi comportamento personalizzato usando l'oggetto stream risultante.

Personalizzare il formato audio

È possibile personalizzare gli attributi di output audio, tra cui:

  • Tipo di file audio
  • Frequenza di campionamento
  • Profondità di bit

Per cambiare il formato audio, usare la funzione setSpeechSynthesisOutputFormat() nell'oggetto SpeechConfig. Questa funzione prevede un'istanza di enum di tipo SpeechSynthesisOutputFormat. Usare il enum per selezionare il formato di output. Per i formati disponili, vedere l’elenco dei formati audio.

Sono disponibili varie opzioni per tipi di file diversi a seconda dei requisiti. Per definizione, i formati non elaborati come Raw24Khz16BitMonoPcm non includono intestazioni audio. Usare i formati non elaborati solo in una di queste situazioni:

  • Si sa che l'implementazione downstream può decodificare un flusso di bit non elaborato.
  • Si prevede di compilare manualmente le intestazioni in base a fattori quali profondità bit, frequenza di campionamento e numero di canali.

Questo esempio specifica un formato RIFF ad alta fedeltà Riff24Khz16BitMonoPcm impostando SpeechSynthesisOutputFormat nell'oggetto SpeechConfig. Analogamente all'esempio della sezione precedente, è possibile usare AudioDataStream per ottenere un flusso in memoria del risultato e quindi scriverlo in un file.

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

Quando si esegue il programma, scrive un file .wav nel percorso specificato.

Usare SSML per personalizzare le caratteristiche vocali

È possibile usare SSML per ottimizzare il tono, la pronuncia, la velocità del parlato, il volume e altri aspetti nell'output della sintesi vocale inviando le richieste da uno schema XML. Questa sezione illustra un esempio di modifica della voce. Per altre informazioni, vedere l'articolo Procedura SSML:

Per iniziare a usare SSML per la personalizzazione, è necessario apportare una piccola modifica che cambia la voce.

  1. Creare prima di tutto un nuovo file XML per la configurazione di SSML nella directory radice del progetto.

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

    In questo esempio, file è ssml.xml. L'elemento radice è sempre <speak>. Il wrapping del testo in un elemento <voice> consente di modificare la voce usando il parametro name. Per l'elenco completo delle voci neurali supportate, vedere Supporto linguistico.

  2. Cambiare la richiesta di sintesi vocale in modo che faccia riferimento al file XML. La richiesta è principalmente la stessa. Anziché usare la funzione SpeakText(), si usa SpeakSsml(). Questa funzione prevede una stringa XML, quindi creare prima di tutto una funzione per caricare un file XML e restituirlo come stringa:

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

    A questo punto, l'oggetto risultante è esattamente lo stesso degli esempi precedenti:

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

Nota

Per modificare la voce senza usare SSML, impostare la proprietà su SpeechConfig tramite SpeechConfig.setSpeechSynthesisVoiceName("en-US-AvaMultilingualNeural");.

Sottoscrivere eventi di sintetizzatore

È possibile ottenere altre informazioni dettagliate sull'elaborazione del testo e sui risultati del riconoscimento vocale. Ad esempio, è possibile sapere quando il sintetizzatore inizia e si arresta oppure si potrebbe voler conoscere altri eventi rilevati durante la sintesi.

Quando si usa SpeechSynthesizer per la sintesi vocale, è possibile sottoscrivere gli eventi in questa tabella:

Event Descrizione Caso d'uso
BookmarkReached Segnala che è stato raggiunto un segnalibro. Per attivare un evento raggiunto da un segnalibro, è necessario un elemento bookmark nel SSML. Questo evento segnala il tempo trascorso dell'audio di output tra l'inizio della sintesi e l'elemento bookmark. La proprietà dell'evento Text è il valore stringa impostato nell'attributo mark del segnalibro. Gli elementi bookmark non vengono pronunciati. È possibile usare l'elemento bookmark per inserire marcatori personalizzati in SSML per ottenere l'offset di ogni marcatore nel flusso audio. L'elemento bookmark può essere usato per fare riferimento a una posizione specifica nella sequenza di testo o tag.
SynthesisCanceled Segnala che la sintesi vocale è stata annullata. È possibile confermare quando la sintesi è annullata.
SynthesisCompleted Segnala che la sintesi vocale è stata completata. È possibile confermare quando la sintesi è stata completata.
SynthesisStarted Segnala che la sintesi vocale è stata completata. È possibile confermare l'avvio della sintesi.
Synthesizing Segnala che la sintesi vocale è in corso. Questo evento viene generato ogni volta che l'SDK riceve un blocco audio dal servizio Voce. È possibile confermare quando la sintesi è in corso.
VisemeReceived Segnala che è stato ricevuto un evento visema. I Visemi vengono spesso usati per rappresentare le posizioni chiave nel parlato osservato. Le pose chiave includono la posizione delle labbra, della mascella e della lingua nella produzione di un particolare fonema. È possibile usare visemi per animare il viso di un personaggio durante la riproduzione dell'audio vocale.
WordBoundary Segnala che è stato ricevuto un limite di parola. Questo evento viene generato all'inizio di ogni nuova parola pronunciata, punteggiatura e frase. L'evento segnala l'offset di tempo della parola corrente, in tick, dall'inizio dell'audio di output. Questo evento segnala anche la posizione del carattere nel testo di input o SSML immediatamente prima della parola che sta per essere pronunciata. Questo evento viene comunemente usato per ottenere posizioni relative del testo e dell'audio corrispondente. Potrebbe essere necessario conoscere una nuova parola e quindi intervenire in base alla tempistica. Ad esempio, è possibile ottenere informazioni che consentono di decidere quando e per quanto tempo evidenziare le parole quando vengono pronunciate.

Nota

Gli eventi vengono generati man mano che i dati audio di output diventano disponibili, che è più veloce della riproduzione in un dispositivo di output. Il chiamante deve sincronizzare in modo appropriato lo streaming e il tempo reale.

Ecco un esempio che illustra come sottoscrivere eventi per la sintesi vocale.

Importante

Se si usa una chiave API, archiviarla in modo sicuro in un'altra posizione, ad esempio in Azure Key Vault. Non includere la chiave API direttamente nel codice e non esporla mai pubblicamente.

Per altre informazioni sulla sicurezza dei servizi di intelligenza artificiale, vedere Autenticare le richieste a Servizi di Azure AI.

È possibile seguire le istruzioni nella guida introduttiva, ma sostituire il contenuto del file SpeechSynthesis.java con il codice Java seguente.

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

È possibile trovare altri esempi di testo per il riconoscimento vocale in GitHub.

Usare un endpoint personalizzato

Dal punto di vista funzionale, l'endpoint personalizzato è identico all'endpoint standard usato per le richieste di sintesi vocale.

Una differenza è che EndpointId deve essere specificato per usare la voce personalizzata tramite Speech SDK. È possibile iniziare con l‘avvio rapido della sintesi vocale e quindi aggiornare il codice con EndpointId e SpeechSynthesisVoiceName.

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

Per usare una voce personalizzata tramite Speech Synthesis Markup Language (SSML), specificare il nome del modello come nome della voce. Questo esempio usa la voce 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>

Eseguire e usare un contenitore

I contenitori del servizio Voce forniscono API di endpoint di query basate su WebSocket a cui si accede tramite Speech SDK e l'interfaccia della riga di comando di Voce. Per impostazione predefinita, l'SDK e l'interfaccia della riga di comando di Voce usano il servizio Voce pubblico. Per usare il contenitore, è necessario modificare il metodo di inizializzazione. Usare un URL host del contenitore invece di chiave e area.

Per altre informazioni sui contenitori, vedere Installare ed eseguire contenitori di Voce con Docker.

Documentazione di riferimento | Pacchetto (npm) | Ulteriori esempi in GitHub | Codice sorgente della libreria

In questa guida pratica vengono illustrati i modelli di progettazione comuni per eseguire la sintesi vocale.

Per altre informazioni sulle aree seguenti, vedere Che cos'è la sintesi vocale?

  • Recupero di risposte come flussi in memoria.
  • Personalizzazione della frequenza di campionamento e della velocità in bit dell'output.
  • Invio di richieste di sintesi tramite Speech Synthesis Markup Language (SSML).
  • Uso di voci neurali.
  • Sottoscrizione di eventi e azioni sui risultati.

Selezionare il linguaggio di sintesi e la voce

La funzionalità sintesi vocale nel servizio Voce supporta più di 400 voci e più di 140 lingue e varianti. È possibile ottenere l'elenco completo o provarle nella Raccolta voci.

Specificare la lingua o la voce di SpeechConfig perché corrispondano al testo di input e usino la voce specificata:

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

Tutte le voci neurali sono multilingue e parlano fluentemente sia la propria lingua che l’inglese. Ad esempio, se il testo di input in inglese è "I'm excited to try text to speech" e si imposta es-ES-ElviraNeural, il testo viene pronunciato in inglese con un accento spagnolo.

Se la voce non parla la lingua del testo di input, il servizio cognitivo di Azure per la voce non creerà audio sintetizzato. Per un elenco completo delle voci neurali supportate, consultare Lingue e voci supportate per il servizio cognitivo di Azure per la voce.

Nota

La voce predefinita è la prima voce restituita per impostazioni locali dall'API dell'elenco voci.

La voce che parla viene determinata in ordine di priorità come indicato di seguito:

  • Se non si imposta SpeechSynthesisVoiceName o SpeechSynthesisLanguage, a parlare sarà la voce predefinita per en-US.
  • Se si imposta solo SpeechSynthesisLanguage, a parlare sarà la voce predefinita per impostazioni locali specificate.
  • Se SpeechSynthesisVoiceName e SpeechSynthesisLanguage sono entrambi impostati, l'impostazione SpeechSynthesisLanguage verrà ignorata. La voce specificata tramite SpeechSynthesisVoiceName sarà quella a parlare.
  • Se l'elemento voce viene impostato tramite Speech Synthesis Markup Language (SSML), le impostazioni SpeechSynthesisVoiceName e SpeechSynthesisLanguage verranno ignorate.

In sintesi, l'ordine di priorità può essere descritto come segue:

SpeechSynthesisVoiceName SpeechSynthesisLanguage SSML Risultato
La voce predefinita per en-US sarà quella a parlare
La voce predefinita per le impostazioni locali specificate sarà quella a parlare.
La voce specificata tramite SpeechSynthesisVoiceName sarà quella a parlare.
La voce specificata tramite SSML sarà quella a parlare.

Eseguire la sintesi vocale

Per eseguire l'output vocale sintetizzato nel dispositivo di output attivo corrente, ad esempio un altoparlante, creare un'istanza AudioConfig usando la funzione statica fromDefaultSpeakerOutput(). Ecco un esempio:

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

Quando si esegue il programma, un audio sintetizzato viene riprodotto dall'altoparlante. Questo risultato è un buon esempio dell'utilizzo più semplice. Si esamini quindi la personalizzazione dell'output e la gestione della risposta di output come flusso in memoria per l'uso di scenari personalizzati.

Ottenere un risultato come flusso in memoria

È possibile usare i dati audio risultanti come flusso in memoria anziché scrivere direttamente in un file. Con il flusso in memoria è possibile creare un comportamento personalizzato:

  • Astrarre la matrice di byte risultante come flusso ricercabile per i servizi downstream personalizzati.
  • Integrare il risultato con altri servizi o API.
  • Modificare i dati audio, scrivere intestazioni .wav personalizzate ed eseguire attività correlate.

È possibile apportare questa modifica all'esempio precedente. Rimuovere il blocco AudioConfig, poiché da questo punto in poi il comportamento di output viene gestito manualmente per un maggior controllo. Passare quindi null per AudioConfig nel costruttore SpeechSynthesizer.

Nota

Se si passa null per AudioConfig, invece di ometterlo come nel precedente esempio di output nell'altoparlante, l'audio non viene riprodotto per impostazione predefinita nel dispositivo di output attivo corrente.

Salvare il risultato in una variabile SpeechSynthesisResult. La proprietà SpeechSynthesisResult.audioData restituisce un valore ArrayBuffer dei dati di output, il tipo di flusso del browser predefinito. Per il codice lato server, eseguire la conversione di ArrayBuffer in un flusso di buffer.

Il codice seguente funziona per il lato 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();
        });
}

È possibile implementare qualsiasi comportamento personalizzato usando l'oggetto ArrayBuffer risultante. ArrayBuffer è un tipo comune da ricevere in un browser e riprodurre da questo formato.

Per qualsiasi codice basato su server, se è necessario usare i dati come flusso, è necessario convertire l'oggetto ArrayBuffer in un flusso:

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

Personalizzare il formato audio

È possibile personalizzare gli attributi di output audio, tra cui:

  • Tipo di file audio
  • Frequenza di campionamento
  • Profondità di bit

Per cambiare il formato audio, usare la proprietà speechSynthesisOutputFormat nell'oggetto SpeechConfig. Questa proprietà prevede un'istanza di enum di tipo SpeechSynthesisOutputFormat. Usare il enum per selezionare il formato di output. Per i formati disponili, vedere l’elenco dei formati audio.

Sono disponibili varie opzioni per tipi di file diversi a seconda dei requisiti. Per definizione, i formati non elaborati come Raw24Khz16BitMonoPcm non includono intestazioni audio. Usare i formati non elaborati solo in una di queste situazioni:

  • Si sa che l'implementazione downstream può decodificare un flusso di bit non elaborato.
  • Si prevede di compilare manualmente le intestazioni in base a fattori quali profondità bit, frequenza di campionamento e numero di canali.

Questo esempio specifica un formato RIFF ad alta fedeltà Riff24Khz16BitMonoPcm impostando speechSynthesisOutputFormat nell'oggetto SpeechConfig. Analogamente all'esempio riportato nella sezione precedente, ottenere i dati audio di ArrayBuffer e interagirvi.

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

Usare SSML per personalizzare le caratteristiche vocali

È possibile usare SSML per ottimizzare il tono, la pronuncia, la velocità del parlato, il volume e altri aspetti nell'output della sintesi vocale inviando le richieste da uno schema XML. Questa sezione illustra un esempio di modifica della voce. Per altre informazioni, vedere Panoramica di Speech Synthesis Markup Language.

Per iniziare a usare SSML per la personalizzazione, è necessario apportare una piccola modifica che cambia la voce.

  1. Creare prima di tutto un nuovo file XML per la configurazione di SSML nella directory radice del progetto.

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

    In questo esempio, è ssml.xml. L'elemento radice è sempre <speak>. Il wrapping del testo in un elemento <voice> consente di modificare la voce usando il parametro name. Per l'elenco completo delle voci neurali supportate, vedere Supporto linguistico.

  2. Cambiare la richiesta di sintesi vocale in modo che faccia riferimento al file XML. La richiesta è essenzialmente la stessa, ma invece di usare la funzione speakTextAsync() si usa speakSsmlAsync(). Questa funzione prevede una stringa XML. Creare una funzione per caricare un file XML e restituirla come stringa:

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

    Per altre informazioni su readFileSync, vedere File system Node.js.

    L’oggetto risultato è esattamente lo stesso degli esempi precedenti.

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

Nota

Per modificare la voce senza usare SSML, è possibile impostare la proprietà su SpeechConfig tramite SpeechConfig.speechSynthesisVoiceName = "en-US-AvaMultilingualNeural";.

Sottoscrivere eventi di sintetizzatore

È possibile ottenere altre informazioni dettagliate sull'elaborazione del testo e sui risultati del riconoscimento vocale. Ad esempio, è possibile sapere quando il sintetizzatore inizia e si arresta oppure si potrebbe voler conoscere altri eventi rilevati durante la sintesi.

Quando si usa SpeechSynthesizer per la sintesi vocale, è possibile sottoscrivere gli eventi in questa tabella:

Event Descrizione Caso d'uso
BookmarkReached Segnala che è stato raggiunto un segnalibro. Per attivare un evento raggiunto da un segnalibro, è necessario un elemento bookmark nel SSML. Questo evento segnala il tempo trascorso dell'audio di output tra l'inizio della sintesi e l'elemento bookmark. La proprietà dell'evento Text è il valore stringa impostato nell'attributo mark del segnalibro. Gli elementi bookmark non vengono pronunciati. È possibile usare l'elemento bookmark per inserire marcatori personalizzati in SSML per ottenere l'offset di ogni marcatore nel flusso audio. L'elemento bookmark può essere usato per fare riferimento a una posizione specifica nella sequenza di testo o tag.
SynthesisCanceled Segnala che la sintesi vocale è stata annullata. È possibile confermare quando la sintesi è annullata.
SynthesisCompleted Segnala che la sintesi vocale è stata completata. È possibile confermare quando la sintesi è stata completata.
SynthesisStarted Segnala che la sintesi vocale è stata completata. È possibile confermare l'avvio della sintesi.
Synthesizing Segnala che la sintesi vocale è in corso. Questo evento viene generato ogni volta che l'SDK riceve un blocco audio dal servizio Voce. È possibile confermare quando la sintesi è in corso.
VisemeReceived Segnala che è stato ricevuto un evento visema. I Visemi vengono spesso usati per rappresentare le posizioni chiave nel parlato osservato. Le pose chiave includono la posizione delle labbra, della mascella e della lingua nella produzione di un particolare fonema. È possibile usare visemi per animare il viso di un personaggio durante la riproduzione dell'audio vocale.
WordBoundary Segnala che è stato ricevuto un limite di parola. Questo evento viene generato all'inizio di ogni nuova parola pronunciata, punteggiatura e frase. L'evento segnala l'offset di tempo della parola corrente, in tick, dall'inizio dell'audio di output. Questo evento segnala anche la posizione del carattere nel testo di input o SSML immediatamente prima della parola che sta per essere pronunciata. Questo evento viene comunemente usato per ottenere posizioni relative del testo e dell'audio corrispondente. Potrebbe essere necessario conoscere una nuova parola e quindi intervenire in base alla tempistica. Ad esempio, è possibile ottenere informazioni che consentono di decidere quando e per quanto tempo evidenziare le parole quando vengono pronunciate.

Nota

Gli eventi vengono generati man mano che i dati audio di output diventano disponibili, che è più veloce della riproduzione in un dispositivo di output. Il chiamante deve sincronizzare in modo appropriato lo streaming e il tempo reale.

Ecco un esempio che illustra come sottoscrivere eventi per la sintesi vocale.

Importante

Se si usa una chiave API, archiviarla in modo sicuro in un'altra posizione, ad esempio in Azure Key Vault. Non includere la chiave API direttamente nel codice e non esporla mai pubblicamente.

Per altre informazioni sulla sicurezza dei servizi di intelligenza artificiale, vedere Autenticare le richieste a Servizi di Azure AI.

È possibile seguire le istruzioni nella guida introduttiva, ma sostituire il contenuto del file SpeechSynthesis.js con il codice Java seguente.

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

È possibile trovare altri esempi di testo per il riconoscimento vocale in GitHub.

Eseguire e usare un contenitore

I contenitori del servizio Voce forniscono API di endpoint di query basate su WebSocket a cui si accede tramite Speech SDK e l'interfaccia della riga di comando di Voce. Per impostazione predefinita, l'SDK e l'interfaccia della riga di comando di Voce usano il servizio Voce pubblico. Per usare il contenitore, è necessario modificare il metodo di inizializzazione. Usare un URL host del contenitore invece di chiave e area.

Per altre informazioni sui contenitori, vedere Installare ed eseguire contenitori di Voce con Docker.

Documentazione di riferimento | Pacchetto (download) | Ulteriori esempi in GitHub

In questa guida pratica vengono illustrati i modelli di progettazione comuni per eseguire la sintesi vocale.

Per altre informazioni sulle aree seguenti, vedere Che cos'è la sintesi vocale?

  • Recupero di risposte come flussi in memoria.
  • Personalizzazione della frequenza di campionamento e della velocità in bit dell'output.
  • Invio di richieste di sintesi tramite Speech Synthesis Markup Language (SSML).
  • Uso di voci neurali.
  • Sottoscrizione di eventi e azioni sui risultati.

Prerequisiti

  • Una sottoscrizione di Azure. È possibile crearne uno gratuitamente.
  • Creare una risorsa Voce nel portale di Azure.
  • Ottenere la chiave e l'area della risorsa Voce. Dopo aver distribuito la risorsa Voce, selezionare Vai alla risorsa per visualizzare e gestire le chiavi.

Installare Speech SDK e gli esempi

Il repository Azure-Samples/cognitive-services-speech-sdk contiene esempi scritti in Objective-C per iOS e Mac. Selezionare un collegamento per visualizzare le istruzioni di installazione per ogni esempio:

Usare un endpoint personalizzato

Dal punto di vista funzionale, l'endpoint personalizzato è identico all'endpoint standard usato per le richieste di sintesi vocale.

Una differenza è che EndpointId deve essere specificato per usare la voce personalizzata tramite Speech SDK. È possibile iniziare con l‘avvio rapido della sintesi vocale e quindi aggiornare il codice con EndpointId e SpeechSynthesisVoiceName.

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

Per usare una voce personalizzata tramite Speech Synthesis Markup Language (SSML), specificare il nome del modello come nome della voce. Questo esempio usa la voce 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>

Eseguire e usare un contenitore

I contenitori del servizio Voce forniscono API di endpoint di query basate su WebSocket a cui si accede tramite Speech SDK e l'interfaccia della riga di comando di Voce. Per impostazione predefinita, l'SDK e l'interfaccia della riga di comando di Voce usano il servizio Voce pubblico. Per usare il contenitore, è necessario modificare il metodo di inizializzazione. Usare un URL host del contenitore invece di chiave e area.

Per altre informazioni sui contenitori, vedere Installare ed eseguire contenitori di Voce con Docker.

Documentazione di riferimento | Pacchetto (download) | Ulteriori esempi in GitHub

In questa guida pratica vengono illustrati i modelli di progettazione comuni per eseguire la sintesi vocale.

Per altre informazioni sulle aree seguenti, vedere Che cos'è la sintesi vocale?

  • Recupero di risposte come flussi in memoria.
  • Personalizzazione della frequenza di campionamento e della velocità in bit dell'output.
  • Invio di richieste di sintesi tramite Speech Synthesis Markup Language (SSML).
  • Uso di voci neurali.
  • Sottoscrizione di eventi e azioni sui risultati.

Prerequisiti

  • Una sottoscrizione di Azure. È possibile crearne uno gratuitamente.
  • Creare una risorsa Voce nel portale di Azure.
  • Ottenere la chiave e l'area della risorsa Voce. Dopo aver distribuito la risorsa Voce, selezionare Vai alla risorsa per visualizzare e gestire le chiavi.

Installare Speech SDK e gli esempi

Il repository Azure-Samples/cognitive-services-speech-sdk contiene esempi scritti in Swift per iOS e Mac. Selezionare un collegamento per visualizzare le istruzioni di installazione per ogni esempio:

Eseguire e usare un contenitore

I contenitori del servizio Voce forniscono API di endpoint di query basate su WebSocket a cui si accede tramite Speech SDK e l'interfaccia della riga di comando di Voce. Per impostazione predefinita, l'SDK e l'interfaccia della riga di comando di Voce usano il servizio Voce pubblico. Per usare il contenitore, è necessario modificare il metodo di inizializzazione. Usare un URL host del contenitore invece di chiave e area.

Per altre informazioni sui contenitori, vedere Installare ed eseguire contenitori di Voce con Docker.

Documentazione di riferimento | Pacchetto (PyPi) | Ulteriori esempi in GitHub

In questa guida pratica vengono illustrati i modelli di progettazione comuni per eseguire la sintesi vocale.

Per altre informazioni sulle aree seguenti, vedere Che cos'è la sintesi vocale?

  • Recupero di risposte come flussi in memoria.
  • Personalizzazione della frequenza di campionamento e della velocità in bit dell'output.
  • Invio di richieste di sintesi tramite Speech Synthesis Markup Language (SSML).
  • Uso di voci neurali.
  • Sottoscrizione di eventi e azioni sui risultati.

Selezionare il linguaggio di sintesi e la voce

La funzionalità sintesi vocale nel servizio Voce supporta più di 400 voci e più di 140 lingue e varianti. È possibile ottenere l'elenco completo o provarle nella Raccolta voci.

Specificare la lingua o la voce di SpeechConfig perché corrispondano al testo di input e usino la voce specificata:

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

Tutte le voci neurali sono multilingue e parlano fluentemente sia la propria lingua che l’inglese. Ad esempio, se il testo di input in inglese è "I'm excited to try text to speech" e si imposta es-ES-ElviraNeural, il testo viene pronunciato in inglese con un accento spagnolo.

Se la voce non parla la lingua del testo di input, il servizio cognitivo di Azure per la voce non creerà audio sintetizzato. Per un elenco completo delle voci neurali supportate, consultare Lingue e voci supportate per il servizio cognitivo di Azure per la voce.

Nota

La voce predefinita è la prima voce restituita per impostazioni locali dall'API dell'elenco voci.

La voce che parla viene determinata in ordine di priorità come indicato di seguito:

  • Se non si imposta SpeechSynthesisVoiceName o SpeechSynthesisLanguage, a parlare sarà la voce predefinita per en-US.
  • Se si imposta solo SpeechSynthesisLanguage, a parlare sarà la voce predefinita per impostazioni locali specificate.
  • Se SpeechSynthesisVoiceName e SpeechSynthesisLanguage sono entrambi impostati, l'impostazione SpeechSynthesisLanguage verrà ignorata. La voce specificata tramite SpeechSynthesisVoiceName sarà quella a parlare.
  • Se l'elemento voce viene impostato tramite Speech Synthesis Markup Language (SSML), le impostazioni SpeechSynthesisVoiceName e SpeechSynthesisLanguage verranno ignorate.

In sintesi, l'ordine di priorità può essere descritto come segue:

SpeechSynthesisVoiceName SpeechSynthesisLanguage SSML Risultato
La voce predefinita per en-US sarà quella a parlare
La voce predefinita per le impostazioni locali specificate sarà quella a parlare.
La voce specificata tramite SpeechSynthesisVoiceName sarà quella a parlare.
La voce specificata tramite SSML sarà quella a parlare.

Sintetizzare la voce in un file

Creare un oggetto SpeechSynthesizer. Questo oggetto esegue le conversioni di sintesi vocale e invia l’output ad altoparlanti, file o altri flussi di output. SpeechSynthesizer accetta come parametri:

  • Oggetto SpeechConfig creato nel passaggio precedente.
  • Oggetto AudioOutputConfig che specifica la modalità di gestione dei risultati di output.
  1. Creare un'istanza AudioOutputConfig per scrivere automaticamente l'output in un file .wav usando il parametro del costruttore filename:

    audio_config = speechsdk.audio.AudioOutputConfig(filename="path/to/write/file.wav")
    
  2. Creare un'istanza di SpeechSynthesizer passando l'oggetto speech_config e l'oggetto audio_config come parametri. Per sintetizzare il parlato e scrivere in un file, eseguire speak_text_async() con una stringa di testo.

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

Quando si esegue il programma, viene creato un file sintetizzato .wav, scritto nel percorso specificato. Questo risultato è un buon esempio dell'utilizzo più semplice. Si esamini quindi la personalizzazione dell'output e la gestione della risposta di output come flusso in memoria per l'uso di scenari personalizzati.

Sintetizzare l'output dell'altoparlante

Per eseguire l'output vocale sintetizzato nel dispositivo di output attivo corrente, ad esempio un altoparlante, configurare il parametro use_default_speaker durante la creazione dell'istanza AudioOutputConfig. Ecco un esempio:

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

Ottenere un risultato come flusso in memoria

È possibile usare i dati audio risultanti come flusso in memoria anziché scrivere direttamente in un file. Con il flusso in memoria è possibile creare un comportamento personalizzato:

  • Astrarre la matrice di byte risultante come flusso ricercabile per i servizi downstream personalizzati.
  • Integrare il risultato con altri servizi o API.
  • Modificare i dati audio, scrivere intestazioni di .wav personalizzate ed eseguire attività correlate.

È possibile apportare questa modifica all'esempio precedente. Rimuovere prima di tutto AudioConfig, perché il comportamento di output viene gestito manualmente da questo punto in poi per un maggior controllo. Passare None per AudioConfig nel costruttore SpeechSynthesizer.

Nota

Se si passa None per AudioConfig, invece di ometterlo come nel precedente esempio di output nell'altoparlante, l'audio non viene riprodotto per impostazione predefinita nel dispositivo di output attivo corrente.

Salvare il risultato in una variabile SpeechSynthesisResult. La proprietà audio_data contiene un oggetto bytes dei dati di output. Questo oggetto può essere gestito manualmente oppure è possibile usare la classe AudioDataStream per gestire il flusso in memoria.

In questo esempio si usa il costruttore AudioDataStream per ottenere un flusso dal risultato.

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

A questo punto, è possibile implementare qualsiasi comportamento personalizzato usando l'oggetto stream risultante.

Personalizzare il formato audio

È possibile personalizzare gli attributi di output audio, tra cui:

  • Tipo di file audio
  • Frequenza di campionamento
  • Profondità di bit

Per cambiare il formato audio, usare la funzione set_speech_synthesis_output_format() nell'oggetto SpeechConfig. Questa funzione prevede un'istanza di enum di tipo SpeechSynthesisOutputFormat. Usare il enum per selezionare il formato di output. Per i formati disponili, vedere l’elenco dei formati audio.

Sono disponibili varie opzioni per tipi di file diversi a seconda dei requisiti. Per definizione, i formati non elaborati come Raw24Khz16BitMonoPcm non includono intestazioni audio. Usare i formati non elaborati solo in una di queste situazioni:

  • Si sa che l'implementazione downstream può decodificare un flusso di bit non elaborato.
  • Si prevede di compilare manualmente le intestazioni in base a fattori quali profondità bit, frequenza di campionamento e numero di canali.

Questo esempio specifica un formato RIFF ad alta fedeltà Riff24Khz16BitMonoPcm impostando SpeechSynthesisOutputFormat nell'oggetto SpeechConfig. Analogamente all'esempio della sezione precedente, è possibile usare AudioDataStream per ottenere un flusso in memoria del risultato e quindi scriverlo in un file.

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

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

Quando si esegue il programma, scrive un file .wav nel percorso specificato.

Usare SSML per personalizzare le caratteristiche vocali

È possibile usare SSML per ottimizzare il tono, la pronuncia, la velocità del parlato, il volume e altri aspetti nell'output della sintesi vocale inviando le richieste da uno schema XML. Questa sezione illustra un esempio di modifica della voce. Per altre informazioni, vedere Panoramica di Speech Synthesis Markup Language.

Per iniziare a usare SSML per la personalizzazione, è necessario apportare una piccola modifica che cambia la voce.

  1. Creare prima di tutto un nuovo file XML per la configurazione di SSML nella directory radice del progetto.

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

    In questo esempio, file è ssml.xml. L'elemento radice è sempre <speak>. Il wrapping del testo in un elemento <voice> consente di modificare la voce usando il parametro name. Per l'elenco completo delle voci neurali supportate, vedere Supporto linguistico.

  2. Cambiare la richiesta di sintesi vocale in modo che faccia riferimento al file XML. La richiesta è principalmente la stessa. Anziché usare la funzione speak_text_async(), si usa speak_ssml_async(). Questa funzione prevede una stringa XML. Prima di tutto, leggere la configurazione di SSML come stringa. Da qui, l'oggetto risultato è esattamente lo stesso degli esempi precedenti.

    Nota

    Se ssml_string contiene  all'inizio della stringa, è necessario rimuovere il formato BOM, in caso contrario il servizio restituirà un errore. A questo scopo, impostare il parametro encoding come segue: 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()
    speech_synthesis_result = speech_synthesizer.speak_ssml_async(ssml_string).get()
    
    stream = speechsdk.AudioDataStream(speech_synthesis_result)
    stream.save_to_wav_file("path/to/write/file.wav")
    

Nota

Per modificare la voce senza usare SSML, è possibile impostare la proprietà su SpeechConfig tramite speech_config.speech_synthesis_voice_name = "en-US-AvaMultilingualNeural".

Sottoscrivere eventi di sintetizzatore

È possibile ottenere altre informazioni dettagliate sull'elaborazione del testo e sui risultati del riconoscimento vocale. Ad esempio, è possibile sapere quando il sintetizzatore inizia e si arresta oppure si potrebbe voler conoscere altri eventi rilevati durante la sintesi.

Quando si usa SpeechSynthesizer per la sintesi vocale, è possibile sottoscrivere gli eventi in questa tabella:

Event Descrizione Caso d'uso
BookmarkReached Segnala che è stato raggiunto un segnalibro. Per attivare un evento raggiunto da un segnalibro, è necessario un elemento bookmark nel SSML. Questo evento segnala il tempo trascorso dell'audio di output tra l'inizio della sintesi e l'elemento bookmark. La proprietà dell'evento Text è il valore stringa impostato nell'attributo mark del segnalibro. Gli elementi bookmark non vengono pronunciati. È possibile usare l'elemento bookmark per inserire marcatori personalizzati in SSML per ottenere l'offset di ogni marcatore nel flusso audio. L'elemento bookmark può essere usato per fare riferimento a una posizione specifica nella sequenza di testo o tag.
SynthesisCanceled Segnala che la sintesi vocale è stata annullata. È possibile confermare quando la sintesi è annullata.
SynthesisCompleted Segnala che la sintesi vocale è stata completata. È possibile confermare quando la sintesi è stata completata.
SynthesisStarted Segnala che la sintesi vocale è stata completata. È possibile confermare l'avvio della sintesi.
Synthesizing Segnala che la sintesi vocale è in corso. Questo evento viene generato ogni volta che l'SDK riceve un blocco audio dal servizio Voce. È possibile confermare quando la sintesi è in corso.
VisemeReceived Segnala che è stato ricevuto un evento visema. I Visemi vengono spesso usati per rappresentare le posizioni chiave nel parlato osservato. Le pose chiave includono la posizione delle labbra, della mascella e della lingua nella produzione di un particolare fonema. È possibile usare visemi per animare il viso di un personaggio durante la riproduzione dell'audio vocale.
WordBoundary Segnala che è stato ricevuto un limite di parola. Questo evento viene generato all'inizio di ogni nuova parola pronunciata, punteggiatura e frase. L'evento segnala l'offset di tempo della parola corrente, in tick, dall'inizio dell'audio di output. Questo evento segnala anche la posizione del carattere nel testo di input o SSML immediatamente prima della parola che sta per essere pronunciata. Questo evento viene comunemente usato per ottenere posizioni relative del testo e dell'audio corrispondente. Potrebbe essere necessario conoscere una nuova parola e quindi intervenire in base alla tempistica. Ad esempio, è possibile ottenere informazioni che consentono di decidere quando e per quanto tempo evidenziare le parole quando vengono pronunciate.

Nota

Gli eventi vengono generati man mano che i dati audio di output diventano disponibili, che è più veloce della riproduzione in un dispositivo di output. Il chiamante deve sincronizzare in modo appropriato lo streaming e il tempo reale.

Ecco un esempio che illustra come sottoscrivere eventi per la sintesi vocale.

Importante

Se si usa una chiave API, archiviarla in modo sicuro in un'altra posizione, ad esempio in Azure Key Vault. Non includere la chiave API direttamente nel codice e non esporla mai pubblicamente.

Per altre informazioni sulla sicurezza dei servizi di intelligenza artificiale, vedere Autenticare le richieste a Servizi di Azure AI.

È possibile seguire le istruzioni nella guida introduttiva, ma sostituire il contenuto di tale file speech-synthesis.py con il codice Python seguente.

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

È possibile trovare altri esempi di testo per il riconoscimento vocale in GitHub.

Usare un endpoint personalizzato

Dal punto di vista funzionale, l'endpoint personalizzato è identico all'endpoint standard usato per le richieste di sintesi vocale.

Una differenza è che endpoint_id deve essere specificato per usare la voce personalizzata tramite Speech SDK. È possibile iniziare con l‘avvio rapido della sintesi vocale e quindi aggiornare il codice con endpoint_id e 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"

Per usare una voce personalizzata tramite Speech Synthesis Markup Language (SSML), specificare il nome del modello come nome della voce. Questo esempio usa la voce 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>

Eseguire e usare un contenitore

I contenitori del servizio Voce forniscono API di endpoint di query basate su WebSocket a cui si accede tramite Speech SDK e l'interfaccia della riga di comando di Voce. Per impostazione predefinita, l'SDK e l'interfaccia della riga di comando di Voce usano il servizio Voce pubblico. Per usare il contenitore, è necessario modificare il metodo di inizializzazione. Usare un URL host del contenitore invece di chiave e area.

Per altre informazioni sui contenitori, vedere Installare ed eseguire contenitori di Voce con Docker.

Informazioni di riferimento sull'API REST di riconoscimento vocale | Informazioni di riferimento sull'API REST di riconoscimento vocale per audio brevi | Ulteriori esempi in GitHub

In questa guida pratica vengono illustrati i modelli di progettazione comuni per eseguire la sintesi vocale.

Per altre informazioni sulle aree seguenti, vedere Che cos'è la sintesi vocale?

  • Recupero di risposte come flussi in memoria.
  • Personalizzazione della frequenza di campionamento e della velocità in bit dell'output.
  • Invio di richieste di sintesi tramite Speech Synthesis Markup Language (SSML).
  • Uso di voci neurali.
  • Sottoscrizione di eventi e azioni sui risultati.

Prerequisiti

  • Una sottoscrizione di Azure. È possibile crearne uno gratuitamente.
  • Creare una risorsa Voce nel portale di Azure.
  • Ottenere la chiave e l'area della risorsa Voce. Dopo aver distribuito la risorsa Voce, selezionare Vai alla risorsa per visualizzare e gestire le chiavi.

Sintesi vocale

Al prompt dei comandi, eseguire questo comando. Inserire questi valori nel comando:

  • Chiave della risorsa Voce
  • Area della risorsa Voce

È anche possibile modificare i valori seguenti:

  • Il valore dell'intestazione X-Microsoft-OutputFormat, che controlla il formato di output audio. Un elenco di formati di output audio supportati è disponibile nelle Informazioni di riferimento sull'API REST di sintesi vocale.
  • La voce di output. Per ottenere un elenco di voci disponibili per l'endpoint del servizio Voce, vedere l'API Elenco voci.
  • File di output. In questo esempio la risposta del server viene indirizzata a un file denominato 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

In questa guida pratica vengono illustrati i modelli di progettazione comuni per eseguire la sintesi vocale.

Per altre informazioni sulle aree seguenti, vedere Che cos'è la sintesi vocale?

  • Recupero di risposte come flussi in memoria.
  • Personalizzazione della frequenza di campionamento e della velocità in bit dell'output.
  • Invio di richieste di sintesi tramite Speech Synthesis Markup Language (SSML).
  • Uso di voci neurali.
  • Sottoscrizione di eventi e azioni sui risultati.

Prerequisiti

  • Una sottoscrizione di Azure. È possibile crearne uno gratuitamente.
  • Creare una risorsa Voce nel portale di Azure.
  • Ottenere la chiave e l'area della risorsa Voce. Dopo aver distribuito la risorsa Voce, selezionare Vai alla risorsa per visualizzare e gestire le chiavi.

Scaricare e installare

Seguire questi passaggi e vedere la guida di Avvio rapido sull'interfaccia della riga di comando di Voce per altri requisiti della piattaforma.

  1. Eseguire il comando seguente dell'interfaccia della riga di comando di .NET per installare l'interfaccia della riga di comando di Voce:

    dotnet tool install --global Microsoft.CognitiveServices.Speech.CLI
    
  2. Eseguire i comandi seguenti per configurare la chiave e l'area della risorsa Voce. Sostituire SUBSCRIPTION-KEY con la chiave della risorsa Voce e REGION con l'area della risorsa Voce.

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

Sintesi vocale in un altoparlante

A questo punto si è pronti per eseguire l'interfaccia della riga di comando per Voce per sintetizzare la sintesi vocale da testo.

  • In una finestra della console passare alla directory che contiene il file binario dell'interfaccia della riga di comando di Voce. Poi eseguire quindi il comando seguente.

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

L'interfaccia della riga di comando per Voce produce il linguaggio naturale in inglese attraverso l’altoparlante del computer.

Sintetizzare la voce in un file

  • Eseguire il comando seguente per sostituire l'output del relatore con un file .wav:

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

L'interfaccia della riga di comando per Voce produce il linguaggio naturale in inglese attraverso il file audio greetings.wav.

Eseguire e usare un contenitore

I contenitori del servizio Voce forniscono API di endpoint di query basate su WebSocket a cui si accede tramite Speech SDK e l'interfaccia della riga di comando di Voce. Per impostazione predefinita, l'SDK e l'interfaccia della riga di comando di Voce usano il servizio Voce pubblico. Per usare il contenitore, è necessario modificare il metodo di inizializzazione. Usare un URL host del contenitore invece di chiave e area.

Per altre informazioni sui contenitori, vedere Installare ed eseguire contenitori di Voce con Docker.

Passaggi successivi