2024-01-08 23:37:00 +08:00
|
|
|
|
|
2024-04-02 15:36:52 +08:00
|
|
|
|
#include <sapi.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <iostream>
|
|
|
|
|
#include <string>
|
|
|
|
|
#include <sphelper.h>
|
|
|
|
|
#include "define.h"
|
|
|
|
|
#include "cinterface.h"
|
|
|
|
|
bool _Speak(std::wstring &Content, const wchar_t *token, int voiceid, int rate, int volume, std::wstring &FileName)
|
|
|
|
|
{
|
|
|
|
|
ISpVoice *pVoice = NULL;
|
2024-01-08 23:37:00 +08:00
|
|
|
|
if (FAILED(::CoInitialize(NULL)))
|
|
|
|
|
return false;
|
|
|
|
|
bool ret = true;
|
|
|
|
|
do
|
|
|
|
|
{
|
2024-04-02 15:36:52 +08:00
|
|
|
|
HRESULT hr = CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice, (void **)&pVoice);
|
|
|
|
|
if (FAILED(hr) || (NULL == pVoice))
|
|
|
|
|
{
|
2024-01-08 23:37:00 +08:00
|
|
|
|
ret = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2024-04-02 15:36:52 +08:00
|
|
|
|
IEnumSpObjectTokens *pSpEnumTokens = NULL;
|
|
|
|
|
if (SUCCEEDED(SpEnumTokens(token, NULL, NULL, &pSpEnumTokens)))
|
|
|
|
|
{
|
2024-01-08 23:37:00 +08:00
|
|
|
|
ULONG ulTokensNumber = 0;
|
|
|
|
|
pSpEnumTokens->GetCount(&ulTokensNumber);
|
2024-04-02 15:36:52 +08:00
|
|
|
|
ISpObjectToken *m_pISpObjectToken;
|
2024-01-08 23:37:00 +08:00
|
|
|
|
|
|
|
|
|
pSpEnumTokens->Item(voiceid, &m_pISpObjectToken);
|
|
|
|
|
pVoice->SetVoice(m_pISpObjectToken);
|
|
|
|
|
pVoice->SetRate(rate);
|
|
|
|
|
pVoice->SetVolume(volume);
|
|
|
|
|
|
2024-04-02 15:36:52 +08:00
|
|
|
|
CComPtr<ISpStream> cpWavStream;
|
|
|
|
|
CComPtr<ISpStreamFormat> cpOldStream;
|
2024-01-08 23:37:00 +08:00
|
|
|
|
CSpStreamFormat originalFmt;
|
|
|
|
|
hr = pVoice->GetOutputStream(&cpOldStream);
|
2024-04-02 15:36:52 +08:00
|
|
|
|
if (FAILED(hr) || (NULL == cpOldStream))
|
|
|
|
|
{
|
2024-01-08 23:37:00 +08:00
|
|
|
|
ret = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
originalFmt.AssignFormat(cpOldStream);
|
|
|
|
|
hr = SPBindToFile(FileName.c_str(), SPFM_CREATE_ALWAYS, &cpWavStream, &originalFmt.FormatId(), originalFmt.WaveFormatExPtr());
|
2024-04-02 15:36:52 +08:00
|
|
|
|
if (FAILED(hr))
|
|
|
|
|
{
|
2024-01-08 23:37:00 +08:00
|
|
|
|
ret = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
pVoice->SetOutput(cpWavStream, TRUE);
|
|
|
|
|
pVoice->Speak(Content.c_str(), SPF_IS_XML, NULL);
|
|
|
|
|
pVoice->Release();
|
|
|
|
|
pSpEnumTokens->Release();
|
|
|
|
|
pVoice = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} while (0);
|
|
|
|
|
|
|
|
|
|
::CoUninitialize();
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-02 15:36:52 +08:00
|
|
|
|
std::vector<std::wstring> _List(const wchar_t *token)
|
|
|
|
|
{
|
2024-01-08 23:37:00 +08:00
|
|
|
|
if (FAILED(::CoInitialize(NULL)))
|
|
|
|
|
return {};
|
2024-04-02 15:36:52 +08:00
|
|
|
|
ISpVoice *pSpVoice = NULL;
|
2024-01-08 23:37:00 +08:00
|
|
|
|
std::vector<std::wstring> ret;
|
2024-04-02 15:36:52 +08:00
|
|
|
|
IEnumSpObjectTokens *pSpEnumTokens = NULL;
|
|
|
|
|
if (FAILED(CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice, (void **)&pSpVoice)))
|
|
|
|
|
{
|
2024-01-08 23:37:00 +08:00
|
|
|
|
return {};
|
|
|
|
|
}
|
2024-04-02 15:36:52 +08:00
|
|
|
|
if (SUCCEEDED(SpEnumTokens(token, NULL, NULL, &pSpEnumTokens)))
|
|
|
|
|
{
|
2024-01-08 23:37:00 +08:00
|
|
|
|
ULONG ulTokensNumber = 0;
|
|
|
|
|
pSpEnumTokens->GetCount(&ulTokensNumber);
|
2024-04-02 15:36:52 +08:00
|
|
|
|
ISpObjectToken *m_pISpObjectToken;
|
2024-01-08 23:37:00 +08:00
|
|
|
|
for (ULONG i = 0; i < ulTokensNumber; i++)
|
|
|
|
|
{
|
|
|
|
|
pSpEnumTokens->Item(i, &m_pISpObjectToken);
|
2024-04-02 15:36:52 +08:00
|
|
|
|
WCHAR *pszVoiceId = NULL;
|
2024-01-08 23:37:00 +08:00
|
|
|
|
LPWSTR pszVoiceName;
|
|
|
|
|
if (SUCCEEDED(m_pISpObjectToken->GetId(&pszVoiceId)))
|
|
|
|
|
{
|
|
|
|
|
// ͨ<><CDA8>ID<49>ַ<EFBFBD><D6B7><EFBFBD><EFBFBD><EFBFBD>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Դ<EFBFBD><D4B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
if (SUCCEEDED(m_pISpObjectToken->GetStringValue(NULL, &pszVoiceName)))
|
|
|
|
|
{
|
|
|
|
|
ret.emplace_back(pszVoiceName);
|
|
|
|
|
CoTaskMemFree(pszVoiceName);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CoTaskMemFree(pszVoiceId);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
m_pISpObjectToken->Release();
|
|
|
|
|
|
|
|
|
|
pSpEnumTokens->Release();
|
|
|
|
|
}
|
|
|
|
|
pSpVoice->Release();
|
|
|
|
|
::CoUninitialize();
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
2024-04-02 15:36:52 +08:00
|
|
|
|
namespace SAPI
|
|
|
|
|
{
|
|
|
|
|
bool Speak(std::wstring &Content, int version, int voiceid, int rate, int volume, std::wstring &FileName);
|
|
|
|
|
std::vector<std::wstring> List(int version);
|
2024-01-08 23:37:00 +08:00
|
|
|
|
constexpr wchar_t SPCAT_VOICES_7[] = L"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Speech\\Voices";
|
|
|
|
|
constexpr wchar_t SPCAT_VOICES_10[] = L"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Speech_OneCore\\Voices";
|
2024-04-02 15:36:52 +08:00
|
|
|
|
};
|
2024-01-08 23:37:00 +08:00
|
|
|
|
|
2024-04-02 15:36:52 +08:00
|
|
|
|
bool SAPI::Speak(std::wstring &Content, int version, int voiceid, int rate, int volume, std::wstring &FileName)
|
|
|
|
|
{
|
|
|
|
|
if (version == 7)
|
|
|
|
|
{
|
2024-01-08 23:37:00 +08:00
|
|
|
|
return _Speak(Content, SPCAT_VOICES_7, voiceid, rate, volume, FileName);
|
|
|
|
|
}
|
2024-04-02 15:36:52 +08:00
|
|
|
|
else if (version == 10)
|
|
|
|
|
{
|
2024-01-08 23:37:00 +08:00
|
|
|
|
return _Speak(Content, SPCAT_VOICES_10, voiceid, rate, volume, FileName);
|
|
|
|
|
}
|
2024-04-02 15:36:52 +08:00
|
|
|
|
else
|
|
|
|
|
{
|
2024-01-08 23:37:00 +08:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-04-02 15:36:52 +08:00
|
|
|
|
std::vector<std::wstring> SAPI::List(int version)
|
|
|
|
|
{
|
|
|
|
|
if (version == 7)
|
|
|
|
|
{
|
2024-01-08 23:37:00 +08:00
|
|
|
|
return _List(SPCAT_VOICES_7);
|
|
|
|
|
}
|
2024-04-02 15:36:52 +08:00
|
|
|
|
else if (version == 10)
|
|
|
|
|
{
|
2024-01-08 23:37:00 +08:00
|
|
|
|
return _List(SPCAT_VOICES_10);
|
|
|
|
|
}
|
2024-04-02 15:36:52 +08:00
|
|
|
|
else
|
|
|
|
|
{
|
2024-01-08 23:37:00 +08:00
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-02 15:36:52 +08:00
|
|
|
|
bool SAPI_Speak(const wchar_t *Content, int version, int voiceid, int rate, int volume, const wchar_t *Filename)
|
|
|
|
|
{
|
|
|
|
|
auto _c = std::wstring(Content);
|
|
|
|
|
auto _f = std::wstring(Filename);
|
|
|
|
|
return SAPI::Speak(_c, version, voiceid, rate, volume, _f);
|
2024-01-08 23:37:00 +08:00
|
|
|
|
}
|
|
|
|
|
|
2024-04-02 15:36:52 +08:00
|
|
|
|
wchar_t **SAPI_List(int version, size_t *num)
|
|
|
|
|
{
|
|
|
|
|
auto _list = SAPI::List(version);
|
2024-01-08 23:37:00 +08:00
|
|
|
|
*num = _list.size();
|
|
|
|
|
return vecwstr2c(_list);
|
|
|
|
|
}
|