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