C# 利用TTS实现文本转语音

时间:2024-02-21 15:44:11

TSS(Text To Speech),语音朗读文本的技术,在Windows*下,微软给我们提供了一套API接口(Speech API)。金山词霸的朗读功能就是用的这个接口。

 

WindowsXP自带的是Speech API 5.1版本,默认只支持英文,如果要支持中文需要安装语音库。

Speech API 5.1 官方下载地址

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