TSS(Text To Speech),語音朗讀文本的技術,在Windows下台下,微軟給我們提供了一套API接口(Speech API)。金山詞霸的朗讀功能就是用的這個接口。
WindowsXP自帶的是Speech API 5.1版本,默認只支持英文,如果要支持中文需要安裝語音庫。
Vista版本開始,系統自帶的Speech API就換成了5.3版本,比較奇怪的是這個API並沒有做到向下兼容,5.3版本在Vista以下的版本是不可用的。
有一些非官方的Windows優化版本去掉了語音功能,需要對系統進行修復。
TTS修復工具及一些其他的語音庫下載
http://www.dacidian.net/tts/
下面我說一下如何實現,使用.NET 4.0新增的dynamic類型,可以很方便的使用COM類庫。
Type type = Type.GetTypeFromProgID("SAPI.SpVoice"); dynamic spVoice = Activator.CreateInstance(type); spVoice.Speak("Text To Speech 語音朗讀文本技術");
當然,直接使用dynamic還是很不方便的,可以對SAPI.SpVoice進行封裝
using System; using System.Collections.Generic; using System.Text; using System.Reflection; using System.Diagnostics; using System.Runtime.InteropServices; namespace COM { [Guid("ED5DCE10-F40B-4655-9E7B-903779C77AF2")] public partial class SpVoice : Object { public enum Flags { SVSFDefault = 0, SVSFlagsAsync = 1, SVSFPurgeBeforeSpeak = 2, SVSFIsFilename = 4, SVSFIsXML = 8, SVSFIsNotXML = 16, SVSFPersistXML = 32, SVSFNLPSpeakPunc = 64, SVSFParseSapi = 128, SVSFParseSsml = 256, SVSFParseAutodetect = 0, SVSFNLPMask = 64, SVSFParseMask = 384, SVSFVoiceMask = 511, SVSFUnusedFlags = -512 } public enum Priority { SVPNormal = 0, SVPAlert = 1, SVPOver = 2 } } public partial class SpVoice : Object { private Type _ComType = null; private object _ComObject = null; public SpVoice() { this.Init(); } public bool Init() { this._ComType = Type.GetTypeFromProgID("SAPI.SpVoice", true); // CLSID {269316D8-57BD-11D2-9EEE-00C04F797396} if (this._ComType == null) { throw new Exception("COM調用失敗"); } this._ComObject = Activator.CreateInstance(this._ComType, true); return this._ComObject != null; } public int Release() { return Marshal.ReleaseComObject(this._ComObject); } public int Rate { get { return (int)this._ComType.InvokeMember("Rate", BindingFlags.GetProperty, null, this._ComObject, null); } set { this._ComType.InvokeMember("Rate", BindingFlags.SetProperty, null, this._ComObject, new object[] { value }); } } public void Pause() { this._ComType.InvokeMember("Pause", BindingFlags.InvokeMethod, null, this._ComObject, null); } public void Resume() { this._ComType.InvokeMember("Resume", BindingFlags.InvokeMethod, null, this._ComObject, null); } public int Volume { get { return (int)this._ComType.InvokeMember("Volume", BindingFlags.GetProperty, null, this._ComObject, null); } set { this._ComType.InvokeMember("Volume", BindingFlags.SetProperty, null, this._ComObject, new object[] { value }); } } public int Skip(int Type, int NumItems) { return (int)this._ComType.InvokeMember("Skip", BindingFlags.InvokeMethod, null, this._ComObject, new object[] { Type, NumItems }); } public bool IsUISupported(string TypeOfUI, object ExtraData) { return (bool)this._ComType.InvokeMember("IsUISupported", BindingFlags.InvokeMethod, null, this._ComObject, new object[] { TypeOfUI, ExtraData }); } public bool WaitUntilDone(int msTimeout) { return (bool)this._ComType.InvokeMember("WaitUntilDone", BindingFlags.InvokeMethod, null, this._ComObject, new object[] { msTimeout }); } public void DisplayUI(int hWndParent, string Title, string TypeOfUI, object ExtraData) { this._ComType.InvokeMember("DisplayUI", BindingFlags.InvokeMethod, null, this._ComObject, new object[] { hWndParent, Title, TypeOfUI, ExtraData }); } public void Speak(string Text, Flags Flags) { this._ComType.InvokeMember("Speak", BindingFlags.InvokeMethod, null, this._ComObject, new object[] { Text, Flags }); } public Priority Property { get { return (Priority)this._ComType.InvokeMember("Priority", BindingFlags.GetProperty, null, this._ComObject, null); } set { this._ComType.InvokeMember("Priority", BindingFlags.SetProperty, null, this._ComType, new object[] { value }); } } public List<string> GetVoices() { List<string> _ret = null; object Item = null, _Voices = this._ComType.InvokeMember("GetVoices", BindingFlags.InvokeMethod, null, this._ComObject, null); int Count = (int)_Voices.GetType().InvokeMember("Count", BindingFlags.GetProperty, null, _Voices, null); if (Count != 0) { _ret = new List<string>(); } for (int i = 0; i < Count; i++) { Item = _Voices.GetType().InvokeMember("Item", BindingFlags.InvokeMethod, null, _Voices, new object[]{ i }); if (Item != null) { _ret.Add(Item.GetType().InvokeMember("GetDescription", BindingFlags.InvokeMethod, null, Item, null).ToString()); } } return _ret; } public bool SetVoices(string Name) { bool _ret = false; object Item = null, _Voices = this._ComType.InvokeMember("GetVoices", BindingFlags.InvokeMethod, null, this._ComObject, null); int Count = (int)_Voices.GetType().InvokeMember("Count", BindingFlags.GetProperty, null, _Voices, null); for (int i = 0; i < Count; i++) { Item = _Voices.GetType().InvokeMember("Item", BindingFlags.InvokeMethod, null, _Voices, new object[] { i }); if (Item != null) { var _str = Item.GetType().InvokeMember("GetDescription", BindingFlags.InvokeMethod, null, Item, null).ToString(); if (_str == Name) { this._ComType.InvokeMember("Voice", BindingFlags.SetProperty, null, this._ComObject, new object[] { Item }); } } } return _ret; } } } 轉載於http://blog.csdn.net/windowsvipcuvs/article/details/30751707
這樣使用起來就比較方便
var spVoices = new SpVoice() { Rate = -2, Volume = 100 }; spVoices.SetVoices(spVoices.GetVoices()[0]); spVoices.Speak(speak, SpVoice.Flags.SVSFlagsAsync);