- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我正在用 3D 模型做一个项目,这很重要。所以,我使用的是 SAPI 5.1,我想在有 Viseme 事件时异步调用一个函数(以便播放与之相关的动画)。
我该怎么做?
非常感谢。
注意:我使用:hRes = m_cpVoice->Speak(L"All I want is to solve this problem", SPF_ASYNC , NULL); 我知道 CspEvent,event.eEventId。我想要的只是当 Sapi 事件发生时如何调用一个函数
最佳答案
首先,您需要调用m_cpVoice->SetInterest (SPFEI(SPEI_VISEME),SPFEI(SPEI_VISEME));这将告诉 SAPI 在 VISEME 事件触发时发送一个事件。
其次,您需要通过调用 m_cpVoice->SetNotifyCallbackInterface 来设置事件处理程序, 与您的回调。 (它必须实现 ISpNotifyCallback ,这是您的对象将实现的虚拟 C++ 接口(interface)。)
你可以看看SAPI events documentation了解更多详情。
ISpNotifyCallback 的示例实现如下所示:
TTSHandler.h:
class CTTSHandler : ISpNotifyCallback
{
public:
CTTSHandler(void);
~CTTSHandler(void);
HRESULT Initialize();
HRESULT DoSpeak();
HRESULT Uninitialize();
private:
HRESULT STDMETHODCALLTYPE NotifyCallback(WPARAM wParam, LPARAM lParam);
void TTSAppStatusMessage(LPCTSTR str);
CComPtr<ISpAudio> m_cpOutAudio;
CComPtr<ISpVoice> m_cpVoice;
HANDLE m_hSpeakDone;
};
TTSHandler.cpp:
#include "TTSHandler.h"
#include <sphelper.h>
CTTSHandler::CTTSHandler(void) : m_hSpeakDone(INVALID_HANDLE_VALUE)
{
}
CTTSHandler::~CTTSHandler(void)
{
}
HRESULT CTTSHandler::Initialize()
{
HRESULT hr = m_cpVoice.CoCreateInstance( CLSID_SpVoice );
if ( SUCCEEDED( hr ) )
{
SpCreateDefaultObjectFromCategoryId( SPCAT_AUDIOOUT, &m_cpOutAudio );
}
if( SUCCEEDED( hr ) )
{
hr = m_cpVoice->SetOutput( m_cpOutAudio, FALSE );
}
if ( SUCCEEDED( hr ) )
{
hr = m_cpVoice->SetNotifyCallbackInterface(this, 0, 0);
}
// We're interested in all TTS events
if( SUCCEEDED( hr ) )
{
hr = m_cpVoice->SetInterest( SPFEI_ALL_TTS_EVENTS, SPFEI_ALL_TTS_EVENTS );
}
if (SUCCEEDED(hr))
{
m_hSpeakDone = ::CreateEvent(NULL, TRUE, FALSE, NULL); // anonymous event used to wait for speech done
}
return hr;
}
HRESULT CTTSHandler::DoSpeak()
{
HRESULT hr = m_cpVoice->Speak( L"This is a reasonably long string that should take a while to speak. This is some more text.", SPF_ASYNC |SPF_IS_NOT_XML, 0 );
if (FAILED(hr))
{
TTSAppStatusMessage( _T("speak failed\r\n") );
}
else
{
BOOL fContinue = TRUE;
while (fContinue)
{
DWORD dwWaitId = ::MsgWaitForMultipleObjectsEx(1, &m_hSpeakDone, INFINITE, QS_ALLINPUT, MWMO_INPUTAVAILABLE);
switch (dwWaitId)
{
case WAIT_OBJECT_0:
{
fContinue = FALSE;
}
break;
case WAIT_OBJECT_0 + 1:
{
MSG Msg;
while (::PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE))
{
::TranslateMessage(&Msg);
::DispatchMessage(&Msg);
}
}
break;
case WAIT_TIMEOUT:
{
hr = S_FALSE;
fContinue = FALSE;
}
break;
default:// Unexpected error
{
TTSAppStatusMessage(L"Unexpected error returned from MsgWaitForMultipleObj");
hr = HRESULT_FROM_WIN32(::GetLastError());
fContinue = FALSE;
}
break;
}
}
}
return hr;
}
HRESULT CTTSHandler::Uninitialize()
{
m_cpVoice = NULL;
return S_OK;
}
void CTTSHandler::TTSAppStatusMessage(LPCTSTR szMessage )
{
wprintf_s(L"%s", szMessage);
}
/////////////////////////////////////////////////////////////////
HRESULT STDMETHODCALLTYPE CTTSHandler::NotifyCallback(WPARAM, LPARAM)
/////////////////////////////////////////////////////////////////
//
// Handles the WM_TTSAPPCUSTOMEVENT application defined message and all
// of it's appropriate SAPI5 events.
//
{
CSpEvent event; // helper class in sphelper.h for events that releases any
// allocated memory in it's destructor - SAFER than SPEVENT
int i = 0;
HRESULT hr = S_OK;
while( event.GetFrom(m_cpVoice) == S_OK )
{
switch( event.eEventId )
{
case SPEI_START_INPUT_STREAM:
TTSAppStatusMessage( _T("StartStream event\r\n") );
break;
case SPEI_END_INPUT_STREAM:
TTSAppStatusMessage( _T("EndStream event\r\n") );
SetEvent(m_hSpeakDone);
break;
case SPEI_VOICE_CHANGE:
TTSAppStatusMessage( _T("Voicechange event\r\n") );
break;
case SPEI_TTS_BOOKMARK:
{
// Get the string associated with the bookmark
// and add the null terminator.
TCHAR szBuff2[MAX_PATH] = _T("Bookmark event: ");
size_t cEventString = wcslen( event.String() ) + 1;
WCHAR *pwszEventString = new WCHAR[ cEventString ];
if ( pwszEventString )
{
wcscpy_s( pwszEventString, cEventString, event.String() );
_tcscat_s( szBuff2, _countof(szBuff2), CW2T(pwszEventString) );
delete[] pwszEventString;
}
_tcscat_s( szBuff2, _countof(szBuff2), _T("\r\n") );
TTSAppStatusMessage( szBuff2 );
}
break;
case SPEI_WORD_BOUNDARY:
TTSAppStatusMessage( _T("Wordboundary event\r\n") );
break;
case SPEI_PHONEME:
TTSAppStatusMessage( _T("Phoneme event\r\n") );
break;
case SPEI_VISEME:
TTSAppStatusMessage( _T("Viseme event\r\n") );
break;
case SPEI_SENTENCE_BOUNDARY:
TTSAppStatusMessage( _T("Sentence event\r\n") );
break;
case SPEI_TTS_AUDIO_LEVEL:
WCHAR wszBuff[MAX_PATH];
swprintf_s(wszBuff, _countof(wszBuff), L"Audio level: %d\r\n", (ULONG)event.wParam);
TTSAppStatusMessage( CW2T(wszBuff) );
break;
case SPEI_TTS_PRIVATE:
TTSAppStatusMessage( _T("Private engine event\r\n") );
break;
default:
TTSAppStatusMessage( _T("Unknown message\r\n") );
break;
}
}
return hr;
}
关于c++ - 在 "event.GetFrom(m_cpVoice)==S_OK"时调用函数(因此事件发生时)[SAPI 5.1 和 C++],我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2866599/
我是 c++ 的新手,尝试编写一个更新函数。 使用 URLDownloadToFile 下载没有问题,但如果我将 url 更改为无效的 url,它仍然返回 S_OK ...如何检查下载是否成功? #i
场景如下: 我有 WSCF Blue 生成的 C# Web 服务客户端,我必须从 C 调用它。我使用 C++ CLI“桥”来完成它。在 C# web 服务客户端我有 namespace MyCompa
在我正在处理的遗留 C++ 代码中,我注意到许多返回 HRESULT 的方法遵循将局部变量设置为 S_OK 的做法,然后在方法末尾返回它而不更改它。 HRESULT function()
如何比较方法返回的值与 HRESULT?我试过了,但它不起作用: FPropStg.DeleteMultiple(1, psProp) == VSConstants.S_OK DeleteMultip
我正在编写一个远程连接到服务器的客户端应用程序。我需要模拟我的客户将与之合作的用户。 这是我的代码的摘录: COAUTHIDENTITY coAuthIdentity, *pCoAuthIdentit
所以我有以下代码: extern ID3D11Device* dev; extern ID3D11DeviceContext* devcon; //shaders
前段时间,我不得不修改一个旧的 COM DLL(Visual C++ 2010,ATL),将它从“Apartment”线程模型迁移到“Both”,即现在可以从 STA 和 MTA 线程调用它而无需序列
我在 Windows 7 中遇到了这个问题。首先我定义了一个实现 IDropTarget 的类。然后,我将 RegisterDragDrop 与放置在我的应用程序窗口中的控件的句柄一起使用。 Regi
我正在使用最新的 Flash 播放器,并从我的开发机器本地提供一个 swf 文件。在一个容器测试应用程序中,我能够播放 swf 并调用它,但在我的“真实”应用程序中,相同的代码路径会导致 com 错误
我正在实现一个 COM 接口(interface),它应该返回 S_OK 或 E_FAIL 的 int 值。我可以返回 S_OK,因为我从另一个调用 (Marshal.QueryInterface)
我目前正在对广泛使用 COM/MFC/(谁知道还有多少其他技术)的项目进行升级。作为升级的一部分,我们正尝试将尽可能多的功能移动到托管 C# 代码中,但不幸的是,有些东西无法移动(出于我不会讨论的原因
我正在用 3D 模型做一个项目,这很重要。所以,我使用的是 SAPI 5.1,我想在有 Viseme 事件时异步调用一个函数(以便播放与之相关的动画)。 我该怎么做? 非常感谢。 注意:我使用:hRe
我是一名优秀的程序员,十分优秀!