Synthese vocale et .Net 3.0 : donnez la parole à vos applications sous Vista
Date de publication : 19/07/2007
Par
Ronald VASSEUR (autres articles)
Au cours de cet article je vais vous présenter un aspect souvent peu aborde,
il s'agit de la synthèse vocale. En effet, peu de développeurs ont eu un jour
l'idée d'intégrer une telle fonctionnalité dans leur application… Pourtant,
si l'on y réfléchit un peu cela pourrait s'avérer utile dans de nombreux domaines
allant de la borne de musée interactive à une application de supervision
d'un quelconque process. Quand un avertissement sonore doit être émis par une
application la méthode le plus souvent employée est la lecture d'un fichier
préenregistré, ici je vous propose de synthétiser de manière dynamique le
message vocal. Pour réaliser cela vous aller voir que Microsoft nous simplifie
grandement la vie. Depuis plusieurs années Microsoft propose gratuitement au
téléchargement un SDK de reconnaissance et de synthèse vocale, depuis Windows
Vista la donne a légèrement changée puisque tout cela est intégré au
Framework .Net 3.0... Cet article porte uniquement sur le développement
d'applications bâties autour de .Net 3.0, et donc ne s'appuyant pas sur
la version 5.1 de SAPI (Speech API) employée pour les versions précédentes de Windows,
mais sur la toute nouvelle version 5.3.
Introduction
1. Presentation de System.Speech
2. Donnons la parole a notre application
3. Allons plus loin
3.1. Choisir la voix à utiliser
3.2. Utilisation de la classe PromptBuilder
3.3. Persistance d'une voix synthetisee
Conclusion
Ressources
Introduction
Il faut tout d'abord bien séparer synthèse et reconnaissance vocale. La synthèse
est la génération d'une voix synthétique à partir d'un texte donné, alors que la
reconnaissance consiste à reconnaitre et à retranscrire sous forme textuelle la
parole d'un utilisateur. Bien que la solution de Microsoft sache faire les deux,
nous allons ici nous intéresser à la synthèse, la reconnaissance fera l'objet
d'un prochain article.
 |
Remarque : la technologie de synthèse vocale proposé par Microsoft comporte à l'heure
actuelle uniquement une voix anglaise et une voix chinoise, donc pour le
français il faudra patienter encore un peu, en espérant que Microsoft ne
nous fera pas trop attendre. Sous Vista, la voix n'est désormais plus
masculine, le bon vieux Sam a été remplace par Anna, et Lili est la
voix Chinoise de Vista.
|
Le code sera proposé en VB.Net et en C#, et je vous le rappelle bien que basé
sur le Framework .Net 3.0 ce qui sera abordé dans cet article ne sera garantit
que pour un fonctionnement sous Vista, en effet la version de SAPI sur laquelle
repose le code de cet article est la 5.3, qui est uniquement disponible sur le nouveau
système d'exploitation de la firme de Redmond. D'ailleurs Vista utilise cette
version 5.3 pour ses fonctionnalités de reconnaissance et de synthèse vocale.
1. Presentation de System.Speech
Une fois n'est pas coutume, en .Net tout se passe dans des namespaces, ici il se
nomme System.Speech. Il contient tout ce dont nous aurons besoin pour synthétiser
une voix et ainsi donner la parole à notre application. Vous devez donc tout
d'abord ajouter une référence vers l'assembly le contenant, il s'agit de System.Speech.dll.
Il ne vous reste plus qu'à ajouter Imports System.Speech.Synthetizer dans votre fichier
de code pour ne pas avoir à taper à chaque fois les noms complets des objets que vous allez utiliser.
Ce namespace s'appuie sur la librairie COM SAPI 5.3 et en reprend la quasi totalité
des fonctionnalités, mais cependant quelques unes ne sont pas présentes, je vous renvoie
à la documentation officielle pour en avoir la liste. Si vous êtes adepte comme moi de
.Net et pas spécialement de COM je vous recommande d'utiliser System.Speech.Synthetizer,
les quelques fonctionnalités absentes par rapport a la libraire COM ne sont pas vitales.
Voici les classes majeures de ce namespace :
- SpeechSynthetizer : c'est la classe la plus importante. Elle contient toutes les methodes permettant de synthetiser la voix.
- PromptBuilder : permet de creer un document qui va servir a synthetiser la voix par l'intermediaire de SpeechSynthetizer. Cette classe permet aussi de serialiser ce document au format SSML.
- PromptStyle : cette classe permet de definir un style a appliquer a un document PromptBuilder, cela pour comprendre la vitesse, le volume, la pronomciation...
2. Donnons la parole a notre application
Commençons par l'exemple le plus simple qui soit, le célébrissime "Hello World".
Nous allons tout d'abord ajouter une référence vers System.Speech.dll, puis ajouter
Imports System.Speech.Synthetizer dans notre classe. A ce stade il nous faut désormais
instancier un objet de type SpeechSynthetizer, c'est lui que nous allons utiliser
pour synthétiser la voix, pour cela cette classe possède la méthode Speak() qui prend
en paramètre le texte qui doit être synthétisé. Voici le code qui nous permet de faire
parler notre application :
| Hello World en VB.Net |
Dim s As New SpeechSynthesizer
s.Speak("Hello World")
|
| Hello World en C# |
SpeechSynthesizer s = new SpeechSynthesizer();
s.Speak("Hello World");
|
Comme vous pouvez le voir c'est d'une complexité folle ! Placez ce code par
exemple dans l'événement Click d'un bouton et il ne reste plus qu'à écouter
la voix "mélodieuse" de votre ordinateur.
Mais voyons plus en détail ce qu'il est possible de faire grâce au Framework
3.0 et plus particulièrement au namespace System.Speech, vous allez voir
c'est très sympathique et cela peut apporter un vrai plus à vos applications.
3. Allons plus loin
Jusqu'ici nous nous sommes contentés de synthétiser de la voix
sans réel contrôle. Nous allons voir que nous pouvons par exemple enregistrer
cette voix dans un fichier, gérer les paramètres de prononciation, le volume,
la vitesse. Une des nouveautés et amélioration de SAPI en version 5.3 est le
support du standard W3C SSML (Speech Synthesis Markup Language) qui permet
d'établir facilement les paramètres (vitesse, prononciation, volume, pauses,
intonations...) de la voix synthétisée. SSML s'appuie sur un ensemble de balises
à la manière de HTML/XML. Ainsi, au lieu de passer une simple chaine de
caractères nous passons une chaine au format SSML qui contient tous
les paramètres souhaités. Un exemple de chaine au format SSML pourrait
être le suivant :
| Exemple de code SSML |
<speak version="1.0" xmlns="http://www.w3.org/2001/10/synthesis" xml:lang="fr-FR">Hello world, welcome on the<sub alias="dot net">.Net</sub>planet!</speak>
|
Ne nous attardons pas plus sur SSML pour le moment, nous y reviendrons plus loin dans cet article.
3.1. Choisir la voix à utiliser
Ici pas de longs discours non plus, car tout d'abord c'est très simple à
réaliser et surtout le choix n'est pas des plus large, en effet
pour l'instant il n'existe sous Vista qu'Anna pour l'anglais, Lili
pour le chinois (à condition que votre Vista dispose du bon pack de langage),
et Sam pour l'anglais sous XP, ce qui n'est pas dans le cadre de cet article. Cependant on peut espérer que Microsoft
élargira ce choix, et de plus il toujours est possible d'ajouter si besoin de nouvelles voix à
votre système d'exploitation, des éditeurs de logiciels spécialisés en proposent.
Voici comment procéder depuis votre application .Net :
| Choisir la voix à utiliser en VB.Net |
Private Sub SelectVoice(ByVal name As String)
Dim s As New SpeechSynthesizer
s.SelectVoice(name)
s.Speak("Hello, my name is Anna")
End Sub
|
| Choisir la voix à utiliser en C# |
private void SelectVoice(string name)
{
SpeechSynthesizer s = new SpeechSynthesizer();
s.SelectVoice(name);
s.Speak("Hello, my name is Anna");
}
|
3.2. Utilisation de la classe PromptBuilder
Si l'on veut éviter d'avoir à écrire cette chaine un peu barbare sans aucune
assistance nous pouvons utiliser la classe PromptBuilder qui permet entre
autre de générer une chaine SSML, mais aussi de définir les paramètres que
l'on veut imposer à la voix synthétisée. En fait, PromptBuilder permet de lire,
de générer du SSML, mais aussi de prendre en entrée des chaines de caractères
simples, des chaines utilisant l'alphabet phonétique, etc. Il s'agit de la
pierre angulaire de System.Speech lorsque l'on veut synthétiser de la voix de manière précise.
Un exemple valant souvent mieux qu'un long discours voici ce qu'il est possible de
faire en mettant en œuvre certaines possibilités de PromptBuilder.
| Exemple d'utilisation de PromptBuilder en VB.Net |
Private Sub PromptBuilderSample()
Dim p As New PromptBuilder()
Dim s1 As New PromptStyle
s1.Volume = PromptVolume.ExtraLoud
s1.Rate = PromptRate.Slow
s1.Emphasis = PromptEmphasis.Reduced
p.StartStyle(s1)
p.StartParagraph()
p.StartSentence()
p.AppendText("Hello world, its's")
p.AppendTextWithHint("07/10/2007", SayAs.Date)
p.EndSentence()
p.EndParagraph()
p.EndStyle()
p.AppendBreak(New TimeSpan(10000000))
Dim s2 As New PromptStyle
s2.Rate = PromptRate.Medium
s2.Volume = PromptVolume.ExtraLoud
s2.Emphasis = PromptEmphasis.Reduced
p.StartStyle(s2)
p.StartParagraph()
p.AppendText("welcome on the")
p.AppendTextWithAlias(".Net", "dot net")
p.AppendText("planet!")
p.EndParagraph()
p.StartParagraph()
p.StartSentence()
p.AppendTextWithHint("VB", SayAs.SpellOut)
p.AppendText("2005 is really a wonderful language !")
p.EndSentence()
p.StartSentence()
p.AppendTextWithHint("SSML", SayAs.SpellOut)
p.AppendText("standard is now included in SAPI")
p.AppendTextWithHint("5.3", SayAs.SpellOut)
p.EndSentence()
p.EndParagraph()
p.EndStyle()
p.AppendBreak(New TimeSpan(10000000))
p.AppendText("Please, visit my website at", PromptRate.Slow)
p.AppendTextWithHint("http://", SayAs.SpellOut)
p.AppendText("webman dot developpez dot com")
Dim synth As New SpeechSynthesizer
synth.SetOutputToWaveFile("c:\voix.wav")
synth.Speak(p)
synth.SetOutputToNull()
End Sub
|
| Exemple d'utilisation de PromptBuilder en C# |
private void PromptBuilderSample()
{
PromptBuilder p = new PromptBuilder();
PromptStyle s1 = new PromptStyle();
s1.Volume = PromptVolume.ExtraLoud;
s1.Rate = PromptRate.Slow;
s1.Emphasis = PromptEmphasis.Reduced;
p.StartStyle(s1);
p.StartParagraph();
p.StartSentence();
p.AppendText("Hello world, its's");
p.AppendTextWithHint("07/10/2007", SayAs.Date);
p.EndSentence();
p.EndParagraph();
p.EndStyle();
p.AppendBreak(new TimeSpan(10000000));
PromptStyle s2 = new PromptStyle();
s2.Rate = PromptRate.Medium;
s2.Volume = PromptVolume.ExtraLoud;
s2.Emphasis = PromptEmphasis.Reduced;
p.StartStyle(s2);
p.StartParagraph();
p.AppendText("welcome on the");
p.AppendTextWithAlias(".Net", "dot net");
p.AppendText("planet!");
p.EndParagraph();
p.StartParagraph();
p.StartSentence();
p.AppendTextWithHint("VB", SayAs.SpellOut);
p.AppendText("2005 is really a wonderful language !");
p.EndSentence();
p.StartSentence();
p.AppendTextWithHint("SSML", SayAs.SpellOut);
p.AppendText("standard is now included in SAPI");
p.AppendTextWithHint("5.3", SayAs.SpellOut);
p.EndSentence();
p.EndParagraph();
p.EndStyle();
p.AppendBreak(new TimeSpan(10000000));
p.AppendText("Please, visit my website at", PromptRate.Slow);
p.AppendTextWithHint("http://", SayAs.SpellOut);
p.AppendText("webman dot developpez dot com");
SpeechSynthesizer synth = new SpeechSynthesizer();
synth.SetOutputToWaveFile("c:\\voix.wav");
synth.Speak(p);
synth.SetOutputToNull();
}
|
Voici quelques membres de la classe PromptBuilder qui méritent que l'on s'attarde dessus. Cette
liste n'est pas exhaustive, et je vous renvoie donc vers la documentation officielle dont le
lien est disponible en fin d'article dans la partie "Ressources".
- AppendAudio() : cette méthode permet d'ajouter le contenu d'un fichier wav a notre objet PromptBuilder.
- AppendText() : cette méthode permet d'ajouter un texte simple à synthétiser, on peut passer en plus à la méthode la vitesse de diction souhaitée pour ce texte.
- AppendTextWithHint() : cette méthode permet également d'ajouter du texte, mais en plus elle permet de définir la manière de prononcer ce texte. Une énumération (SayAs) nous permet de choisir parmi une liste de prononciation définie, cela sera par exemple épeler le texte, le prononcer comme une date ou comme une heure…
- AppendTextWithAlias() : comme les deux précédentes cette méthode permet d'ajouter du texte a synthétiser mais elle permet de définir un alias qui correspondra a la manière de prononcer le texte qui peut être différente de la manière dont il est écrit. Un exemple simple pourrait être " .Net " que l'on veut prononcer comme " dot net ".
- AppendBreak() : cette méthode permet de marquer une pause, une rupture dans la lecture, qui peut être plus ou moins longue.
- StartStyle() / End Style() : permettent de définir un style (vitesse, volume, emphase…) pour le texte inclus entre ces deux méthodes. L'exemple que je donne un peu plus haut vous donne un bon aperçu de ce qu'il est possible de faire avec un objet PromptStyle.
- StartParagraph()/EndParagraph() : permettent de délimiter un paragraphe.
- StartSentence()/EndSentence() : permettent de délimiter une phrase.
- SayAs : cette énumération contient les prononciations prédéfinies que l'on peut entre autre spécifier en paramètre de la méthode AppendTextWithHint() que l'on vient de voir. Voici le contenu exhaustif de cette énumération : Date, Day, DayMonth, DayMonthYear, Month, MonthDay, MonthDayYear, MonthYear, NumberCardinal, NumberOrdinal, SpellOut, Telephone, Text, Time, Time12, Time24, Year, YearMonth, YearMonthDay
Je vous propose maintenant de voir comment PromptBuilder peut générer
du SSML ou prendre du SSML en entrée. Tout d'abord, pour générer du
SSML il faut utiliser la méthode ToXml() de la classe PromptBuilder,
ca n'est pas plus complique que ca. Cette méthode retourne une chaine
contenant le code SSML représentant la voix que l'on souhaite synthétiser.
Si l'on veut conserver ces données SSML dans un fichier il suffit
d'utiliser simplement un objet StreamWriter.
| Exporter la chaine SSML directement dans un fichier en VB.Net |
Private Sub PromptBuilderToSsmlFile()
Dim p As New PromptBuilder()
p.AppendText("Hello world, welcome on the")
p.AppendTextWithAlias(".Net", "dot net")
p.AppendText("planet!")
Using sw As New StreamWriter("c:\monfichier.ssml")
sw.Write(p.ToXml())
End Using
End Sub
|
| Exporter la chaine SSML directement dans un fichier en C# |
private void PromptBuilderToSsmlFile()
{
PromptBuilder p = new PromptBuilder();
p.AppendText("Hello world, welcome on the");
p.AppendTextWithAlias(".Net", "dot net");
p.AppendText("planet!");
using (StreamWriter sw = new StreamWriter("c:\\monfichier.ssml")) {
sw.Write(p.ToXml());
}
}
|
 |
Remarque : attention, j'utilise ici Using qui s'occupe de la gestion du StreamWriter,
dans d'autres circonstances il faudrait penser a fermer le StreamWriter avec la méthode Close().
|
Voyons comment maintenant importer du SSML directement dans notre
objet PromptBuilder. Pour cela il existe deux méthodes qui sont
AppendSsml() et AppendSsmlMarkup(). La première prends en paramètre
le chemin d'un fichier contenant le code SSML, la deuxième quand a
elle prend en directement en paramètre une chaine au format SSML.
Voici un exemple d'utilisation de ces méthodes.
| *** |
Private Sub AppendSsml()
Dim p As New PromptBuilder()
p.AppendSsml("c:\fichier.ssml")
p.AppendSsmlMarkup("remplacer ce texte par votre chaine SSML")
Dim s As New SpeechSynthesizer
s.Speak(p)
End Sub
|
| *** |
private void AppendSsml()
{
PromptBuilder p = new PromptBuilder();
p.AppendSsml("c:\\fichier.ssml");
p.AppendSsmlMarkup("remplacer ce texte par votre chaine SSML");
SpeechSynthesizer s = new SpeechSynthesizer();
s.Speak(p);
}
|
 |
Remarque : dans cette partie nous venons de voir que l'objet PromptBuilder
est tres souple en termes de sources de texte à synthétiser, cela peut être
des chaines des caractères simples, du SSML, du wav, en flux, en fichier, etc.
Et tout cela est possible pour un même objet, il est donc envisageable de combiner
différentes sources sans pour autant avoir à les contraindre préalablement dans
un format donné. A l'usage cela se révèle très appréciable.
|
Voyons maintenant comment faire persister la voix que l'on a synthétisée.
3.3. Persistance d'une voix synthetisee
Si l'on veut faire persister une voix synthétisée ou pourquoi pas l'échanger
entre différentes machines et pourquoi pas plateforme, nous avons deux possibilités
principales : enregistrer la voix dans un fichier Wav (le format étant supporté
sur de nombreuses plateformes) ou la sérialiser au format SSML. La deuxième
solution est évidemment dans la majorité des situations la meilleure, d'autant
plus que SSML est un standard W3C largement adopté.
Enregistrement de la voix dans un fichier Wav :
| Synthétiser un PromptBuilder dans un fichier Wav en VB.Net |
Private Sub PromptBuilderToWavFile()
Dim p As New PromptBuilder
p.AppendTextWithHint("VB", SayAs.SpellOut)
p.AppendTextWithAlias(".Net", "dot net")
p.AppendText("is the nicest language for .Net platform !")
Dim synth As New SpeechSynthesizer
synth.SetOutputToWaveFile("c:\voix.wav")
synth.Speak(p)
synth.SetOutputToNull()
End Sub
|
| Synthétiser un PromptBuilder dans un fichier Wav en C# |
private void PromptBuilderToWavFile()
{
PromptBuilder p = new PromptBuilder();
p.AppendTextWithHint("VB", SayAs.SpellOut);
p.AppendTextWithAlias(".Net", "dot net");
p.AppendText("is the nicest language for .Net platform !");
SpeechSynthesizer synth = new SpeechSynthesizer();
synth.SetOutputToWaveFile("c:\\voix.wav");
synth.Speak(p);
synth.SetOutputToNull();
}
|
Sérialisation SSML de la voix :
| Sérialisation d'un PromptBuilder en VB.Net |
Private Function PromptBuilderToSsml() As String
Dim p As New PromptBuilder
p.AppendTextWithHint("VB", SayAs.SpellOut)
p.AppendTextWithAlias(".Net", "dot net")
p.AppendText("is the nicest language for .Net platform !")
Return p.ToXml
End Function
|
| Sérialisation d'un PromptBuilder en C# |
private string PromptBuilderToSsml()
{
PromptBuilder p = new PromptBuilder();
p.AppendTextWithHint("VB", SayAs.SpellOut);
p.AppendTextWithAlias(".Net", "dot net");
p.AppendText("is the nicest language for .Net platform !");
return p.ToXml;
}
|
 |
Remarque : attention au wav, il s'agit d'un format non compresse,
et donc le volume du fichier peut rapidement augmenter, même s'il est
possible d'ajuster les paramètres d'enregistrement il faudra garder
à l'esprit ce détail. Voici un argument de plus en faveur d'une
sérialisation SSML de la voix, plutôt que d'un enregistrement
dans un fichier wav.
|
 |
Info : si vous souhaitez en savoir plus sur le SSML un lien vers la documentation de
ce format est disponible dans la partie "Ressources" de cet article.
|
Conclusion
J'espère que cet article vous aura donné l'envie de tester la synthèse vocale sous Vista, et pourquoi
pas même de l'intégrer dans vos prochaines applications. Il serait cependant souhaitable que Microsoft
ajoute de nouvelles voix en plus de celles de Lili et d'Anna. Nous avons vu que System.Speech comporte
une partie synthèse, mais aussi une partie reconnaissance vocale qui fera
l'objet d'un prochain article.
Un grand merci à AGM26 pour la relecture de cet article, ainsi qu'à l'équipe Dotnet pour son aide.
Ressources


Copyright © 2007 Ronald Vasseur. Aucune reproduction, même partielle, ne peut être faite
de ce site et de l'ensemble de son contenu : textes, documents, images, etc
sans l'autorisation expresse de l'auteur.
Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E
de dommages et intérêts.
Cette page est déposée à la
SACD.