goldendict-ng/speechhlp.cc

158 lines
3.5 KiB
C++
Raw Normal View History

#define WINVER 0x0500 // At least WinXP required
#include <windows.h>
#include "speechhlp.hh"
#include <string>
#include "sapi.hh"
#include "sphelper.hh"
using std::wstring;
struct _SpeechHelper
{
ISpVoice * voice;
wstring engineId;
wstring engineName;
bool willInvokeCoUninitialize;
_SpeechHelper() : willInvokeCoUninitialize(false)
{
HRESULT hr;
hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
willInvokeCoUninitialize = (hr != RPC_E_CHANGED_MODE);
CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_INPROC_SERVER, IID_ISpVoice, (void**)&voice );
}
~_SpeechHelper()
{
if (voice)
voice->Release();
if (willInvokeCoUninitialize)
CoUninitialize();
}
};
static bool findByEngineName(void *token, const wchar_t *id, const wchar_t *name, void *userData)
{
SpeechHelper sp = (SpeechHelper)userData;
if (sp->engineId == id)
{
sp->voice->SetVoice((ISpObjectToken *)token);
sp->engineName = name;
return false;
}
return true;
}
SpeechHelper speechCreate(const wchar_t *engineId)
{
SpeechHelper sp = new _SpeechHelper();
sp->engineId = engineId;
speechEnumerateAvailableEngines(findByEngineName, sp);
return sp;
}
void speechDestroy(SpeechHelper sp)
{
delete sp;
}
bool speechAvailable(SpeechHelper sp)
{
if (!sp)
return false;
return !!(sp->voice);
}
void speechEnumerateAvailableEngines(EnumerateCallback callback, void *userData)
{
HRESULT hr;
IEnumSpObjectTokens * enumSpTokens;
ULONG count = 0;
bool next = true;
hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
bool willInvokeCoUninitialize = (hr != RPC_E_CHANGED_MODE);
hr = SpEnumTokens(SPCAT_VOICES, NULL, NULL, &enumSpTokens);
if (SUCCEEDED(hr))
hr = enumSpTokens->GetCount(&count);
for (ULONG i = 0; i < count && next; i++)
{
ISpObjectToken * spToken = NULL;
WCHAR * engineName = NULL;
WCHAR * engineId = NULL;
if (SUCCEEDED(hr))
hr = enumSpTokens->Next(1, &spToken, NULL);
if (SUCCEEDED(hr))
hr = SpGetDescription(spToken, &engineName);
if (SUCCEEDED(hr))
hr = spToken->GetId(&engineId);
if (SUCCEEDED(hr))
next = callback(spToken, engineId, engineName, userData);
if( spToken )
spToken->Release();
if (engineName)
CoTaskMemFree(engineName);
if (engineId)
CoTaskMemFree(engineId);
}
if( enumSpTokens )
enumSpTokens->Release();
if (willInvokeCoUninitialize)
CoUninitialize();
}
const wchar_t * speechEngineId(SpeechHelper sp)
{
if (!sp)
return NULL;
return sp->engineId.c_str();
}
const wchar_t * speechEngineName(SpeechHelper sp)
{
if (!sp)
return NULL;
return sp->engineName.c_str();
}
bool speechTell(SpeechHelper sp, const wchar_t *text)
{
if (!sp || !sp->voice || !text)
return false;
HRESULT hr = sp->voice->Speak(text, SPF_ASYNC | SPF_IS_NOT_XML, 0);
return !!SUCCEEDED(hr);
}
bool speechTellFinished(SpeechHelper sp)
{
if (!sp || !sp->voice)
return true;
SPVOICESTATUS es;
sp->voice->GetStatus(&es, NULL);
return es.dwRunningState == SPRS_DONE;
}
bool speechSay(SpeechHelper sp, const wchar_t *text)
{
if (!sp || !sp->voice || !text)
return false;
HRESULT hr = sp->voice->Speak(text, SPF_IS_NOT_XML, 0);
return !!SUCCEEDED(hr);
}