/// <summary> /// Stops the engine if it is running. /// </summary> public static void Stop() { lock (syncLock) { if (!isRunning) { return; } cache.Stop(); cache = null; isRunning = false; } }
private static Dictionary <string, string> voiceNameMap; // Maps friendly voice names to the internal name /// <summary> /// Starts the engine if it is not already running. /// </summary> /// <param name="settings">The engine settings.</param> /// <exception cref="ArgumentNullException">Thrown if <paramref name="settings"/> is <c>null</c>.</exception> public static void Start(SpeechEngineSettings settings) { if (settings == null) { throw new ArgumentNullException("settings"); } lock (syncLock) { if (SpeechEngine.isRunning) { return; } SpeechEngine.settings = settings; SpeechEngine.cache = new PhraseCache(settings); SpeechEngine.isRunning = true; // Create the default audio formats. format_8000KHz = new SpeechAudioFormatInfo(8000, AudioBitsPerSample.Eight, AudioChannel.Mono); format_11025KHz = new SpeechAudioFormatInfo(11025, AudioBitsPerSample.Eight, AudioChannel.Mono); format_16000KHz = new SpeechAudioFormatInfo(16000, AudioBitsPerSample.Eight, AudioChannel.Mono); // Get the fully qualified paths to the error files. noVoicesPath = Path.Combine(CoreApp.InstallPath, "Audio", "NoVoicesError.wav"); synthErrorPath = Path.Combine(CoreApp.InstallPath, "Audio", "SpeechSynthError.wav"); // Enumerate the installed voices and select the default voice. // // Note: The Microsoft Speech Platform voices have really clunky names like: // // "Microsoft Server Speech Text to Speech Voice (en-AU, Hayley)" // // I'm going to simplify these to be just "Microsoft <name>" and maintain // a table that maps back to the original name. voiceNameMap = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase); using (var synth = new SpeechSynthesizer()) { var voices = new Dictionary <string, VoiceInfo>(StringComparer.OrdinalIgnoreCase); foreach (var voice in synth.GetInstalledVoices()) { var voiceName = voice.VoiceInfo.Name; if (!voice.Enabled) { continue; } // $hack(jeff.lill): // // Make sure that the voice can actually be used. I've run into // situations where [Microsoft Anna] was present and enabled but // could not be selected. I believe this may be a 64-bit issue // or perhaps installing Cepstral voices messes with Anna. try { synth.SelectVoice(voice.VoiceInfo.Name); } catch { continue; } if (voiceName.StartsWith("Microsoft Server Speech Text to Speech Voice (")) { int p = voiceName.IndexOf(','); if (p != -1) { voiceName = voiceName.Substring(p + 1); voiceName = "Microsoft " + voiceName.Replace(")", string.Empty).Trim(); voiceNameMap[voiceName] = voice.VoiceInfo.Name; } } voices.Add(voiceName, voice.VoiceInfo); } SpeechEngine.InstalledVoices = voices.ToReadOnly(); SpeechEngine.DefaultVoice = null; SpeechEngine.DefaultVoiceInfo = null; // First see if the desired default voice exists. if (!string.IsNullOrWhiteSpace(settings.DefaultVoice) && String.Compare(settings.DefaultVoice, "auto") != 0) { VoiceInfo voiceInfo; if (voices.TryGetValue(settings.DefaultVoice, out voiceInfo)) { SpeechEngine.DefaultVoice = voiceInfo.Name; } else { SysLog.LogWarning("[SpeechEngine] was not able to locate the requested default voice [{0}]. Another voice will be selected automatically.", settings.DefaultVoice); } } // If not look for an alternative if (SpeechEngine.DefaultVoice == null) { if (voices.ContainsKey("Microsoft Helen")) { SpeechEngine.DefaultVoice = "Microsoft Helen"; } else if (voices.ContainsKey("Microsoft Anna")) { SpeechEngine.DefaultVoice = "Microsoft Anna"; } else { SysLog.LogWarning("[SpeechEngine] was not able to locate the [Microsoft Anna] voice."); var v = voices.Keys.FirstOrDefault(); if (v == null) { SpeechEngine.DefaultVoice = null; SysLog.LogError("[SpeechEngine] was not able to locate any speech synthesis voices. Speech synthesis will be disabled."); } else { SpeechEngine.DefaultVoice = v; } } } if (SpeechEngine.DefaultVoice != null) { SpeechEngine.DefaultVoiceInfo = SpeechEngine.InstalledVoices[GetVoice(SpeechEngine.DefaultVoice)]; } } } }