实验二 语音交互设计TTS基于图形用户界面_人机交互tts语音朗读
实验二 语音交互设计TTS基于图形用户界面由刀豆文库小编整理,希望给你工作、学习、生活带来方便,猜你可能喜欢“人机交互tts语音朗读”。
COM:即组件对象模型,Component Object Model。
1、在COM构架下,人们可以开发出各种各样的功能专一的组件,组件实际上是一些小的二进制可执行程序,它们可以给应用程序、操作系统以及其他组件提供服务,然后将它们按照需要组合起来,构成复杂的应用系统(如dll)。优点:可用新组件替换原有组件,系统升级和定制更加简便;可在多个应用系统中重复利用同一个组件;可以方便的将应用系统扩展到网络环境下;COM与语言、平台无关,程序员可充分发挥自己的才智与专长编写组件模块等。
2、使用和处理COM对象。COM独立于语言,COM为自己提供对象管理例程。COM中创建对象,实际是调用COM库中的API函数CoCreatInstance().调用该函数时,在注册表中查找COM服务器位置,将服务器加载到内存,并创建所请求的实例。
3、一般使用COM对象的步骤是: 初始化COM库(Initialize);
创建一个COM对象,获得相应接口;
如果对象创建成功,则调用COM对象的某个方法; 释放接口;
收回COM库(Uninitialize)
二、TTS—基于图形界面
基于图形用户界面创建一个TTS应用程序,通过对菜单命令的选择执行文本-语音的转换。
一、建立项目
1、创建一个实现典型“Hello world”应用的windows 32平台应用程序项目。
二、设置sapi路径:与SAPI相关的文件路径必须在项目中声明。(sapi.h和sapi.lib)
1、选择“Tools”→ “Options”→“Directories”选项卡;
2、选择“Include Files”下拉式选单,增加“sapi.h”的文件路径;
3、选择“Library Files”下拉式选单,增加“sapi.lib”的文件路径;
三、创建“Speak”菜单命令
1、修改自动生成的菜单项。打开“资源管理器”→“File”菜单→增加“Speak”命令项→资源ID设置为“IDM_SPEAK”。
四、实现speak功能 第1步:初始化COM 第2步:创建语音对象设置声音 第3步:调用speak函数 第4步:设置感兴趣的事件 第5步:确定事件类型 第6步:响应事件
1、初始化COM if(FAILED(CoInitialize(NULL)))
{
return FALSE;
}
2、创建语音对象设置声音
一旦com运行后,下一步就是要创建语音对象。这里需要用到CoCreatInstance().为简洁和方便起见,这个例子使用了特别的处理方式。首先,它使用initinstance()来初始化声音。这是最简单的初始化过程。第二,这个语音对象是全局性的。第三,语音对象建立之后,对象本省和用到的内存立即被释放。最后,如果初始化失败,应用程序应该有更强有力的检查错误机,更广泛的报告和更详细的资料。
程序清单2:
ISpVoice *pVoice;//SAPI voice(初始化模块)……
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow){。。。
// Instead of using IDC_TEST, use the identifier of menu resource of the current application.SetMenu(hWnd, LoadMenu(hInstance, MAKEINTRESOURCE(IDC_TEST)));ShowWindow(hWnd, nCmdShow);UpdateWindow(hWnd);//Initialize SAPI
HRESULT hr = CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice,(void **)&pVoice);
if(SUCCEEDED(hr))
{
pVoice->SetInterest(SPFEI(SPEI_WORD_BOUNDARY),SPFEI(SPEI_WORD_BOUNDARY));
pVoice->SetNotifyWindowMeage(hWnd, WM_USER, 0, 0);
}
else
return FALSE;
3、调用Speak函数实现“讲话”的功能
要让计算机讲话只需一句简单的调用命令,要讲话的内容用一个参数传给语音对象,常是从一个对话框或一个文件获取字符串的。另外,字符串也可以从一个流中获取,但就要使用另外一个调用 ispvoice:: speakstream。Speak函数的调用代码是放在windows的消息处理函数wndproc()相应的消息处理中的。从文件菜单选择Speak命令,计算机将开始讲: “我很高兴发言。” 程序代码3: // FUNCTION: WndProc(HWND, unsigned, WORD, LONG)。。。
LRESULT CALLBACK WndProc(HWND hWnd, UINT meage, WPARAM wParam, LPARAM lParam){
。。。WCHAR tempString[30]。。。
switch(wmId){。。。case IDM_SPEAK:
wcscpy(theString, L“I am glad to speak.”);
pVoice->Speak(theString, SPF_ASYNC, NULL);
pVoice->Speak(L“I am glad to speak”, SPF_ASYNC, NULL);
break;
default:
return DefWindowProc(hWnd, meage, wParam, lParam);}
4、设置事件
像其它大部分windows应用程序一样,在COM组件中有很多交互动作,这些交互信息将以信息形式出现。sapi是也一样。信息是在TTS或SR引擎中产生的,某个特定的事件也是在那里开始和结束的.很多时候, sapi或sapi的引擎产生的事件是对应用程序有用的。举例来说,当一个识别过程开始的时候,应用程序会得到相应的通知或消息,最终的用户也可以得到相应的通知。
(1)首先,需要接收一个来自sapi的或sapi的引擎的消息。这个消息是程序自定义的.但是,所有的活动sapi都使用相同的消息通知应用程序;
(2)得到通知后,应用程序要检查一个事件结构,这个事件结构是由SAPI完成的.利用这个结构来确定具体是发生了什么事件(见第五步骤).(3)设定感兴趣的事件。程序可以用setinterest 来设置感兴趣的事件。默认情况下,TTS不向程序发出任何事件通知。也就是说,如果程序忽略了setinterest的调用,TTS应用程序是得不到任何事件通知的。
(4)设定消息。不论以何种事件,应用程序都应该将一个消息与sapi联系起来。程序通过调用setnotifywindowmeage来完成这个任务,本例使用WM_USER消息。
程序清单4:
//Initialize SAPI HRESULT hr = CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice,(void **)&pVoice);if(SUCCEEDED(hr)){
pVoice->SetInterest(SPFEI(SPEI_WORD_BOUNDARY),SPFEI(SPEI_WORD_BOUNDARY));
pVoice->SetNotifyWindowMeage(hWnd, WM_USER, 0, 0);
} else return FALSE;
5、确定事件。使用事件来工作需要2个步骤。
(1)首先是使用一个简单和标准的做法设置和使用Windows消息。消息是被发送到程序的消息环中的。在这个例子里,wndproc()接收wm_user讯息。一旦讯息是捕获,其余事情由sapi函数来完成。
(2)第二个步骤是确定哪些消息发生了。Sapi使用 spevent和getevents方法来确定具体的事件和消息。通过这两个函数可以获取指定的事件信息和事件类型。在SPEVENT的成员eeventid恰恰是setinterest所设定的值。该spevent结构必须在首次使用时被初始化。而且重新使用之前也要被清除。可以使用spclearevent来完成清除工作。
程序清单5:
switch(meage)
{
case WM_COMMAND:
wmId
= LOWORD(wParam);
wmEvent = HIWORD(wParam);
。。。
case WM_USER: //处理speak命令的窗口
SPEVENT eventItem;
memset(&eventItem, 0,sizeof(SPEVENT));
while(pVoice->GetEvents(1, &eventItem, NULL)== S_OK)
{
switch(eventItem.eEventId)
{
case SPEI_WORD_BOUNDARY :
SPVOICESTATUS eventStatus;
pVoice->GetStatus(&eventStatus, NULL);
ULONG start, end;
start = eventStatus.ulInputWordPos;
end = eventStatus.ulInputWordLen;
wcsncpy(tempString, theString + start , end);
tempString[ end ] = '/0';
//MeageBoxW(hWnd, tempString, L“GUIApp”, MB_OK|MB_ICONWARNING);
MeageBoxW(hWnd, tempString, L“SayApp”, MB_OK|MB_ICONWARNING);
break;
default:
break;
}
SpClearEvent(&eventItem);
}
break。。。case WM_DESTROY:
if(pVoice)
{
pVoice->Release();
pVoice = NULL;
}
PostQuitMeage(0);
break;
default:
return DefWindowProc(hWnd, meage, wParam, lParam);
}
6、响应事件。在这个例子中,应用程序使用spei_word_boundary消息来取定每一个单词。可以用getstatus函数和spvoicestatus结构来获取更详细的信息。一个独立的单词,可以用事件发生时的第一个字母和最后一个字母的位置来确定。在这个例子中,使用MeageBoxW来显示所讲的单词。在说话过程中,屏幕是实时更新的,并显示实际发言的文字。这个特点是由spf_async标志控制的。如果在Speak函数中使用NULL参数,而不是SPF_ASYNC参数,那样就要等整句话说完之后,才显示消息框。pVoice->Speak(theString, SPF_ASYNC, NULL);
//释放语音对象
程序代码6:
case SPEI_WORD_BOUNDARY : SPVOICESTATUS eventStatus;
pVoice->GetStatus(&eventStatus, NULL);
ULONG start, end;
start = eventStatus.ulInputWordPos;
end = eventStatus.ulInputWordLen;
wcsncpy(tempString, theString + start , end);
tempString[ end ] = '/0';MeageBoxW(hWnd, tempString, L“GUIApp”, MB_OK|MB_ICONWARNING);break;总结:
最后,总结一下这个例子的主要知识点: 1,初始化COM: CoInitialize和CoUninitialize 2,建立语音对象实例:CoCreateInstance 3,讲话:Speak 4,设置感兴趣的事件:SetInterest
设定SAPI返回的消息 :setnotifywindowmeage 5,消息来时,确定事件类型:GetEvents 清除事件结构:SpClearEvent 6,响应事件时,用GetStatus确定当前SAPI的状态