[Oxford Project] Text To Speech via Azure
Depuis quelques mois, un projet de Microsoft Research permet d’effectuer d’effectuer des traitements sur le son, telles que la reconnaissance vocale, en se basant sur des algorithmes puissants.
La feature la plus facile à prendre en main pour débuter avec le projet Oxford est le TTS ou Text To Speech permettant de convertir un texte en un audio en déléguant le traitement à un service Azure.
Voyons comment procéder.
1. Création du service Azure Oxford
Voici le point d’entrée pour la partie Speech du projet Oxford https://www.projectoxford.ai/speech
Celui-ci va en réalité vous renvoyer vers Azure pour créer le service adapté.
Voici donc un résumé des étapes :
Une fois votre service créé, pensez à récupérer les clés “clientId” et “clientSecret” qui nous seront nécessaires par la suite. Pour le faire, suivez ce petit lien dans la page de gestion de votre service :
2. Créer le client C#
Microsoft fournit un SDK. Cool ! On a rien à coder alors ? Malheureusement le seul SDK dispo pour le moment est pour… Android. ET oui, on va tout refaire à la main alors. Go !
2.1 Authentification
Pour utiliser le service Oxford, votre programme doit pouvoir s'authentifier auprès de celui-ci.
Nous allons donc commencer par créer une classe Authentication dont le but sera de gérer l'authentification.
Pour cela, trois données seront nécessaires : le clientId, le clientSecret et bien sûr, l'url du service.
Une simple requête HTTP POST utilisant ces paramètres permet de faire le boulot.
Voici donc un extrait du code vous permettant de créer la classe Authentication :
public static readonly string AccessUri = "https://oxford-speech.cloudapp.net/token/issueToken"; //Create the request to get token from service var request = string.Format("grant_type=client_credentials&client_id={0}&client_secret={1}&scope={2}", Uri.EscapeUriString(clientId), Uri.EscapeUriString(clientSecret), Uri.EscapeUriString("https://speech.platform.bing.com")); var httpClient = new HttpClient(); byte[] bytes = Encoding.ASCII.GetBytes(request); HttpContent httpContent = new ByteArrayContent(bytes); httpContent.Headers.Add("Content-Type", "application/x-www-form-urlencoded"); //Send the request and extract token var result = httpClient.PostAsync(accessUri, httpContent).Result; result.EnsureSuccessStatusCode(); var stream = result.Content.ReadAsStreamAsync().Result; DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(AccessTokenInfo)); //Get deserialized object from JSON stream AccessTokenInfo token = (AccessTokenInfo)serializer.ReadObject(stream); //return the created token return token;
Bien évidemment, je vous invite à sauvegarder les clés et le token et de mettre en place un système de renouvèlement du token lorsque celui-ci arrive à expiration (toutes les 10 minutes).
2.2. Appel du service Azure
Pour appeler le service Oxford, il nous faut déjà connaitre son url que voici : https://speech.platform.bing.com/synthesize
Ensuite, il nous faut connaitre les paramètres nécessaires pour nous faire comprendre du service :
· Le texte
· Le type de voix (male, female)
· La "locale" utilisée (ex: fr-FR)
· Le nom de la voix à utiliser : "Microsoft Server Speech Text to Speech Voice (fr-FR, Julie, Apollo)"
· Le format de sortie (ex: "riff-16khz-16bit-mono-pcm")
· Le token d'authentification au format "Bearer " + le token généré dans l'étape précédente
Pour la plupart des paramètres, la documentation du service vous aidera à connaitre les possibilités qui vous sont offertes.
Dans un premier temps nous allons donc créer le client HTTP et initialiser l'Uri que nous allons utiliser :
var requestUri = new Uri(requestUri);
Pour communiquer avec le service nous devons donc passer certains de ces paramètres dans le header de la requête :
List<KeyValuePair<string, string>> headers = new List<KeyValuePair<string, string>>(); headers.Add(new KeyValuePair<string, string>("Content-Type", "application/ssml+xml")); headers.Add(new KeyValuePair<string, string>("X-Microsoft-OutputFormat", "riff-16khz-16bit-mono-pcm")); // authorization Header headers.Add(new KeyValuePair<string, string>("Authorization", this.AuthorizationToken)); // ClientID and Client Secret from Azure Oxford Speech Service headers.Add(new KeyValuePair<string, string>("X-Search-AppId", "**************")); headers.Add(new KeyValuePair<string, string>("X-Search-ClientID", "**************")); // The software originating the request headers.Add(new KeyValuePair<string, string>("User-Agent", "TTSClient"));
Ce qui nous donne ensuite, pour la création de la requête :
var client = new HttpClient(); // Ajout des paramêtres dans le header : foreach (var header in headers) { client.DefaultRequestHeaders.TryAddWithoutValidation(header.Key, header.Value); }
var content = new StringContent(String.Format(SsmlTemplate, locale, genderValue, voiceName, textToTranslate)); var response = await client.PostAsync(requestUri, content); Stream httpStream = await response.Content.ReadAsStreamAsync();
3. Jouer ou sauvegarder le son
Pour jouer le fichier son généré par le service depuis votre application, vous n'aurez donc plus qu'à appeler une méthode exploitant le stream comme celle-ci :
static void PlayAudio(object sender, GenericEventArgs<Stream> args) { Console.WriteLine(args.EventData); // For SoundPlayer to be able to play the wav file, it has to be encoded in PCM. // Use output audio format AudioOutputFormat.Riff16Khz16BitMonoPcm to do that. SoundPlayer player = new SoundPlayer(args.EventData); player.PlaySync(); args.EventData.Dispose(); }
En revanche vous n'aurez pas forcément envie de lire le son depuis l'application l'ayant généré. Dans ce cas-là le stream pourra être sauvegardé.
Vous devrez reconstruire un fichier au format wav que vous pourrez alors sauvegarder dans votre bibliothèque Musique par exemple :
private static async void SaveAudio(object sender, Stream stream) { var folder = KnownFolders.MusicLibrary; StorageFile file = await folder.CreateFileAsync("music\\meteo.wav", CreationCollisionOption.ReplaceExisting); using (Stream fileStream = await file.OpenStreamForWriteAsync()) { const int BUFFER_SIZE = 1024; byte[] buf = new byte[BUFFER_SIZE]; int bytesread = 0; while ((bytesread = await stream.ReadAsync(buf, 0, BUFFER_SIZE)) > 0) { await fileStream.WriteAsync(buf, 0, bytesread); } } stream.Dispose(); }
Have fun et à bientôt pour de la reconnaissance vocale !
Commentaires