微软语音技术 Windows 语音编程初步

一、SAPI简介

软件中的语音技术包括两方面的内容,一个是语音识别(speech recognition) 和语音合成(speech synthesis)。这两个技术都需要语音引擎的支持。微软推出的应用编程接口API,虽然现在不是业界标准,但是应用比较广泛。

SAPI全称 The Microsoft Speech API.相关的SR和SS引擎位于Speech SDK开发包中。这个语音引擎支持多种语言的识别和朗读,包括英文、中文、日文等。

SAPI包括以下组件对象(接口):

(1)Voice Commands API。对应用程序进行控制,一般用于语音识别系统中。识别某个命令后,会调用相关接口是应用程序完成对应的功能。如果程序想实现语音控制,必须使用此组对象。
(2)Voice Dictation API。听写输入,即语音识别接口。
(3)Voice Text API。完成从文字到语音的转换,即语音合成。
(4)Voice Telephone API。语音识别和语音合成综合运用到电话系统之上,利用此接口可以建立一个电话应答系统,甚至可以通过电话控制计算机。
(5)Audio Objects API。封装了计算机发音系统。

SAPI是架构在COM基础上的,微软还提供了ActiveX控件,所以不仅可用于一般的windows程序,还可以用于网页、VBA甚至EXCEL的图表中。如果对COM感到陌生,还可以使用微软的C++ WRAPPERS,它用C++类封装了语音SDK COM对象。

二、安装SAPI SDK。

首先从这个站点下载开发包:http://www.microsoft.com/speech/download/sdk51

Microsoft Speech SDK 5.1添加了Automation支持。所以可以在VB,ECMAScript等支持Automation的语言中使用。

版本说明:
Version: 5.1
发布日期: 8/8/2001
语音: English
下载尺寸: 2.0 MB - 288.8 MB

这个SDK开发包还包括了可以随便发布的英文和中文的语音合成引擎(TTS),和英文、中文、日文的语音识别引擎(SR)。

系统要求98以上版本。编译开发包中的例子程序需要vc6以上环境。

******下载说明******:
(1)如果要下载例子程序,说明文档,SAPI以及用于开发的美国英语语音引擎,需要下载SpeechSDK51.exe,大约68M。
(2)如果想要使用简体中文和日文的语音引擎,需要下载SpeechSDK51LangPack.exe。大约82M。
(3)如果想要和自己的软件一起发布语音引擎,需要下载SpeechSDK51MSM.exe,大约132M。
     (在这个地址,我未能成功下载)。
(4)如果要获取XP下的 Mike 和 Mary 语音,下载Sp5TTIntXP.exe。大约3.5M。
(5)如果要获取开发包的文档说明,请下载sapi.chm。大约2.3M。这个在sdk51里面已经包含。

下载完毕后,首先安装SpeechSDK51.exe,然后安装中文语言补丁包SpeechSDK51LangPack,然后展开
msttss22l,自动将所需dll安装到系统目录。

三、配置vc环境

在vc6.0的环境下编译语音工程,首先要配置编译环境。假设sdk安装在d:/Microsoft Speech SDK 5.1/路径下,打开工程设置对话框,在c/c++栏中选择Preprocessor分类,然后在"附加包含路径"中输入
d:/Microsoft Speech SDK 5.1/include
告诉vc编译程序所需的SAPI头文件的位置。
然后切换到LINK栏,在Input分类下的附加库路径中输入:
d:/Microsoft Speech SDK 5.1/lib/i386
使vc在链接的时候能够找到sapi.lib。

四、语音合成的应用。即使用SAPI实现TTS(Text to Speech)。

1、首先要初始化语音接口,一般有两种方式:
   ISpVoice* pVoice;
   ::CoInitialize(NULL);
   HRESULT hr = CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice,
               (void **)&pVoice);
   然后就可以使用这个指针调用SAPI函数了,例如
   pVoice->SetVolume(50);//设置音量
   pVoice->Speak(str.AllocSysString(),SPF_ASYNC,NULL);

另外也可以使用如下方式:
    CComPtr<ISpVoice>   m_cpVoice;
    HRESULT  hr = m_cpVoice.CoCreateInstance( CLSID_SpVoice );
   在下面的例子中都用这个m_cpVoice变量。

CLSID_SpVoice的定义位于SPAI.H中。

2、获取/设置输出频率。

SAPI朗读文字的时候,可以采用多种频率方式输出声音,比如:
   8kHz 8Bit Mono、8kHz 8Bit Stereo、44kHz 16Bit Mono、44kHz 16Bit Stereo等。在音调上有所差别。具体可以参考sapi.h。

可以使用如下代码获取当前的配置:
   CComPtr<ISpStreamFormat> cpStream;
   HRESULT hrOutputStream = m_cpVoice->GetOutputStream(&cpStream);
   if (hrOutputStream == S_OK)
   {
       CSpStreamFormat Fmt;
       hr = Fmt.AssignFormat(cpStream);
       if (SUCCEEDED(hr))
       {
           SPSTREAMFORMAT eFmt = Fmt.ComputeFormatEnum();
       }
   }
    SPSTREAMFORMAT 是一个ENUM类型,定义位于SPAI.H中。每一个值对应了不同的频率设置。例如 SPSF_8kHz8BitStereo  = 5

通过如下代码设置当前朗读频率:
    CComPtr<ISpAudio>   m_cpOutAudio; //声音输出接口
    SpCreateDefaultObjectFromCategoryId( SPCAT_AUDIOOUT, &m_cpOutAudio ); //创建接口

SPSTREAMFORMAT eFmt = 21; //SPSF_22kHz 8Bit Stereo

CSpStreamFormat Fmt;
    Fmt.AssignFormat(eFmt);
    if ( m_cpOutAudio )
    {
 hr = m_cpOutAudio->SetFormat( Fmt.FormatId(), Fmt.WaveFormatExPtr() );
    }
    else  hr = E_FAIL;

if( SUCCEEDED( hr ) )
   {
       m_cpVoice->SetOutput( m_cpOutAudio, FALSE );
   }

3、获取/设置播放所用语音。

引擎中所用的语音数据文件一般保存在SpeechEngines下的spd或者vce文件中。安装sdk后,在注册表中保存了可用的语音,比如英文的男/女,简体中文的男音等。位置是:
   HKEY_LOCAL_MACHINE/Software/Microsoft/Speech/Voices/Tokens
如果安装在中文操作系统下,则缺省所用的朗读语音是简体中文。SAPI的缺点是不能支持中英文混读,在朗读中文的时候,遇到英文,只能逐个字母读出。所以需要程序自己进行语音切换。

(1) 可以采用如下的函数把当前SDK支持的语音填充在一个组合框中:
    // SAPI5 helper function in sphelper.h
    HWND hWndCombo = GetDlgItem( hWnd, IDC_COMBO_VOICES ); //组合框句柄
    HRESULT hr = SpInitTokenComboBox( hWndCombo , SPCAT_VOICES );
    这个函数是通过IEnumSpObjectTokens接口枚举当前可用的语音接口,把接口的说明文字添加到组合框中,并且把接口的指针作为LPARAM
    保存在组合框中。
    一定要记住最后程序退出的时候,释放组合框中保存的接口:
    SpDestroyTokenComboBox( hWndCombo );
    这个函数的原理就是逐个取得combo里面每一项的LPARAM数据,转换成IUnknown接口指针,然后调用Release函数。
(2) 当组合框选择变化的时候,可以用下面的函数获取用户选择的语音:
    ISpObjectToken* pToken = SpGetCurSelComboBoxToken( hWndCombo );

(3) 用下面的函数获取当前正在使用的语音:
    CComPtr<ISpObjectToken> pOldToken;
    HRESULT hr = m_cpVoice->GetVoice( &pOldToken );
(4) 当用户选择的语音和当前正在使用的不一致的时候,用下面的函数修改:
    if (pOldToken != pToken)
    {       
         // 首先结束当前的朗读,这个不是必须的。
         HRESULT hr = m_cpVoice->Speak( NULL, SPF_PURGEBEFORESPEAK, 0);
         if (SUCCEEDED (hr) )
        {
            hr = m_cpVoice->SetVoice( pToken );
         }
    }
(5) 也可以直接使用函数SpGetTokenFromId获取指定voice的Token指针,例如:
      WCHAR pszTokenId[] = L"HKEY_LOCAL_MACHINE//Software//Microsoft//Speech//Voices//Tokens//MSSimplifiedChineseVoice";
    SpGetTokenFromId(pszTokenID , &pChineseToken);

4、开始/暂停/恢复/结束当前的朗读
  
   要朗读的文字必须位于宽字符串中,假设位于szWTextString中,则:
   开始朗读的代码:
   hr = m_cpVoice->Speak( szWTextString, SPF_ASYNC | SPF_IS_NOT_XML, 0 );
   如果要解读一个XML文本,用:
   hr = m_cpVoice->Speak( szWTextString, SPF_ASYNC | SPF_IS_XML, 0 );

暂停的代码:   m_cpVoice->Pause();
   恢复的代码:   m_cpVoice->Resume();
   结束的代码:(上面的例子中已经给出了)
   hr = m_cpVoice->Speak( NULL, SPF_PURGEBEFORESPEAK, 0);

5、跳过部分朗读的文字

在朗读的过程中,可以跳过部分文字继续后面的朗读,代码如下:
   ULONG ulGarbage = 0;
   WCHAR szGarbage[] = L"Sentence";
   hr = m_cpVoice->Skip( szGarbage, SkipNum, &ulGarbage );
   SkipNum是设置要跳过的句子数量,值可以是正/负。
   根据sdk的说明,目前SAPI仅仅支持SENTENCE这个类型。SAPI是通过标点符号来区分句子的。

6、播放WAV文件。SAPI可以播放WAV文件,这是通过ISpStream接口实现的:

CComPtr<ISpStream>       cpWavStream;
   WCHAR                    szwWavFileName[NORM_SIZE] = L"";;

USES_CONVERSION;
   wcscpy( szwWavFileName, T2W( szAFileName ) );//从ANSI将WAV文件的名字转换成宽字符串

//使用sphelper.h 提供的这个函数打开 wav 文件,并得到一个 IStream 指针
   hr = SPBindToFile( szwWavFileName, SPFM_OPEN_READONLY, &cpWavStream );
   if( SUCCEEDED( hr ) )
   {
        m_cpVoice->SpeakStream( cpWavStream, SPF_ASYNC, NULL );//播放WAV文件
   }
7、将朗读的结果保存到wav文件
   TCHAR szFileName[256];//假设这里面保存着目标文件的路径
   USES_CONVERSION;
   WCHAR m_szWFileName[MAX_FILE_PATH];
   wcscpy( m_szWFileName, T2W(szFileName) );//转换成宽字符串

//创建一个输出流,绑定到wav文件
   CSpStreamFormat OriginalFmt;
   CComPtr<ISpStream>  cpWavStream;
   CComPtr<ISpStreamFormat>    cpOldStream;
   HRESULT hr = m_cpVoice->GetOutputStream( &cpOldStream );
   if (hr == S_OK) hr = OriginalFmt.AssignFormat(cpOldStream);
   else  hr = E_FAIL;
   // 使用sphelper.h中提供的函数创建 wav 文件
   if (SUCCEEDED(hr))
   {
      hr = SPBindToFile( m_szWFileName, SPFM_CREATE_ALWAYS, &cpWavStream,
                         &OriginalFmt.FormatId(), OriginalFmt.WaveFormatExPtr() );
    }
   if( SUCCEEDED( hr ) )
   {
      //设置声音的输出到 wav 文件,而不是 speakers
      m_cpVoice->SetOutput(cpWavStream, TRUE);
    }
    //开始朗读
    m_cpVoice->Speak( szWTextString, SPF_ASYNC | SPF_IS_NOT_XML, 0 );

//等待朗读结束
    m_cpVoice->WaitUntilDone( INFINITE );
    cpWavStream.Release();

//把输出重新定位到原来的流
    m_cpVoice->SetOutput( cpOldStream, FALSE );
  
8、设置朗读音量和速度
   m_cpVoice->SetVolume((USHORT)hpos); //设置音量,范围是 0 - 100
   m_cpVoice->SetRate(hpos);  //设置速度,范围是 -10 - 10

hpos的值一般位于

9、设置SAPI通知消息。SAPI在朗读的过程中,会给指定窗口发送消息,窗口收到消息后,可以主动获取SAPI的事件,
   根据事件的不同,用户可以得到当前SAPI的一些信息,比如正在朗读的单词的位置,当前的朗读口型值(用于显
   示动画口型,中文语音的情况下并不提供这个事件)等等。

要获取SAPI的通知,首先要注册一个消息:
   m_cpVoice->SetNotifyWindowMessage( hWnd, WM_TTSAPPCUSTOMEVENT, 0, 0 );
   这个代码一般是在主窗口初始化的时候调用,hWnd是主窗口(或者接收消息的窗口)句柄。WM_TTSAPPCUSTOMEVENT
   是用户自定义消息。

在窗口响应WM_TTSAPPCUSTOMEVENT消息的函数中,通过如下代码获取sapi的通知事件:

CSpEvent        event;  // 使用这个类,比用 SPEVENT结构更方便

while( event.GetFrom(m_cpVoice) == S_OK )
    {
        switch( event.eEventId )
        {
           。。。
        }
    }

eEventID有很多种,比如SPEI_START_INPUT_STREAM表示开始朗读,SPEI_END_INPUT_STREAM表示朗读结束等。
   可以根据需要进行判断使用。

需要的留下Email,我给大家发

再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow

原文地址:https://www.cnblogs.com/wicnwicnwh/p/10308271.html

时间: 2024-11-02 14:11:17

微软语音技术 Windows 语音编程初步的相关文章

基于科大讯飞语音云windows平台开发

前记: 前段时间公司没事干,突发奇想想做一个语音识别系统,看起来应该很简单的,但做起来却是各种问题,这个对电气毕业的我,却是挺为难的.谷姐已经离我们而去,感谢度娘,感谢CSDN各位大神,好歹也做的是那么回事了,虽然还是不好用,但基本功能实现了. 该软件使用VS2008C++/CLR开发,由于科大讯飞提供的是C的API接口,结果到这边就是各种不兼容,CLR是基于托管堆运行的,而这个API有是非托管堆的,使用了各种指针,原本打算使用C#来做,最后门外汉的我也没能做到C#和C指针完美结合,真怀恋单片机

廉价的语音技术

语音和图像.视频一样,是人与人之间沟通的交流方式. 语音信号处理是一门综合性的学科,它与语音学.心理学.数字信号处理.计算机科学.模式识别等有着密切联系. 语音技术一般可以分为三大类: 1.人与人之间的通信:语音增强.语音编码.语音通信.VOIP等 简单的说,以网络为载体,实现人与人之间的语音通信,涉及到语音前端去噪,增强,语音压缩编码等. 语音增强.语音去噪等, 主要解决的是前端问题,单纯的语音.音频处理技术主要应用在嵌入式方向. 语音编码,做标准的很少,单纯做算法的也很少.主要需求集中围绕着

百度强势入场,AI们集体打 call:揭秘百度智能客服背后的语音技术与应用

两年前的今天,AI流行下围棋:今天,AI流行打电话-- 这个潮流的最近一次上演,是几天前的百度AI开发者大会上,李彦宏现场播放了百度AI客服邀请开发者的真实电话录音. 当时我就在现场,第一通电话里那位开发者方言比较重,到底说了什么我基本没听懂.但百度的AI却应对自如,在电话中回答了各种问题. 第二通电话更神了,那位女开发者发现了小度的AI身份,直接问百度给ta发钱吗,结果被小度用一句"百度给我免费充电",巧妙的"回撩"了过去. 在众人的惊叹中,我们很容易发现让AI打

网络语音技术

浅谈网络语音技术 当我们使用像Skype.QQ这样的工具和朋友流畅地进行语音视频聊天时,我们可曾想过其背后有哪些强大的技术在支撑?本文将对网络语音通话所使用到的技术做一些简单的介绍,算是管中窥豹吧. 一.概念模型 网络语音通话通常是双向的,就模型层面来说,这个双向是对称的.为了简单起见,我们讨论一个方向的通道就可以了.一方说话,另一方则听到声音.看似简单而迅捷,但是其背后的流程却是相当复杂的.我们将其经过的各个主要环节简化成下图所示的概念模型: 这是一个最基础的模型,由五个重要的环节构成:采集.

windows核心编程 DLL技术 【转】

注:本文章转载于网络,源地址为:http://blog.csdn.net/ithzhang/article/details/7051558 本篇文章将介绍DLL显式链接的过程和模块基地址重定位及模块绑定的技术. 第一种将DLL映射到进程地址空间的方式是直接在源代码中引用DLL中所包含的函数或是变量,DLL在程序运行后由加载程序隐式的载入,此种方式被称为隐式链接. 第二种方式是在程序运行时,通过调用API显式的载入所需要的DLL,并显式的链接所想要链接的符号.换句话说,程序在运行时,其中的一个线程

浅谈网络语音技术

转自:http://www.cnblogs.com/zhuweisky/archive/2012/06/08/2514889.html 当我们使用像Skype.QQ这样的工具和朋友流畅地进行语音视频聊天时,我们可曾想过其背后有哪些强大的技术在支撑?本文将对网络语音通话所使用到的技术做一些简单的介绍,算是管中窥豹吧. 一.概念模型 网络语音通话通常是双向的,就模型层面来说,这个双向是对称的.为了简单起见,我们讨论一个方向的通道就可以了.一方说话,另一方则听到声音.看似简单而迅捷,但是其背后的流程却

C++windows内核编程笔记day14 其他线程同步技术

线程同步技术: 原子锁 临界区(段) 互斥 事件 信号量(线程示例时已经使用过) 可等候定时器 使用范围:原子锁<临界区<互斥 效率:    原子锁>临界区(用户态)>互斥(内核态) 一般用临界区. //等候多个信号 DWORD WaitForMultipleObjects( DWORD nCount,             // number of handles in array CONST HANDLE *lpHandles,  // object-handle array

高清语音技术(WBS)及其在手机和蓝牙耳机中的实现

高清语音也被称为宽带语音,是一种能为蜂窝网络.移动电话和无线耳机传输高清.自然语音质量的音频技术.与传统的窄带电话相比,高清语音很大程度上提高了语音质量,减少了听觉负担. 通信产业链上的所有网络和设备都需支持高清语音才能体现出该技术的优点.到2011年6月为止,18个国家运营的20种蜂窝网络,以及33家领先的手机品牌都已支持高清语音.通过部署自适应多速率宽带(AMR-WB)语音编码,GSM, WCDMA(UMTS)和LTE蜂窝网络中已经引入了高清语音.此外, 通过使用改良的子带编码(mSBC)语

Windows游戏编程之从零开始d

I'm back~~恩,几个月不见,大家还好吗? 这段时间真的好多童鞋在博客里留言说或者发邮件说浅墨你回来继续更新博客吧. woxiangnifrr童鞋说每天都在来浅墨的博客逛一下看有没有更新,"每天都来就像看女神那般不依不舍",弄得我再不更新都不好意思了,哈哈~怎么说呢,前段时间忙毕设,回国,暑假,间隔年旅行休整,然后是适应新的生活,各种事情,也真正没有心境来更新博客了,最近正好心境安定下来,就继续开始写博.额,关于思想汇报改天我专门写一篇文章和大家交流交流,现在先打住说正事吧~ 首