//头文件
/*
文件名:tts_module.h
2018年4月23日11:04:18
代码目的:把文字(英语或者汉字)转化成wav文件。可以播放。即TTS text to speech。
*/
class String2Speech
{
public:
//string to wchar*
static WCHAR* str_to_wcharstr(std::string mystring)
{
int mystringSize = (int)(mystring.length()+1);
wchar_t* mywstring = new wchar_t[mystringSize];
MultiByteToWideChar( CP_ACP, 0, mystring.c_str(), -1, mywstring, mystringSize );
return mywstring;
}
static bool ConvertTTS(std::string str, char *SzFileName);
};
经过代码走读,头文件修改成如下:
class String2Speech
{
public:
virtual ~String2Speech(){}
static bool ConvertTTS(const std::string& Content, const std::string& FileName);
};
头文件的实现如下:
/*
2018年4月23日11:06:25
代码功能:实现tts_module.h头文件中的函数。完成TTS
*/
#include "stdafx.h"
#include <sapi.h>
#include <sphelper.h>
#include "tts_module.h"
#include <time.h>
using namespace std;
/** @fn bool String2Speech::ConvertTTS(string str, char *SzFileName)
* @brief 实现std::string转换为wav文件
* @param str [in] 传入的std::string,将其转换为wav文件
* @param SzFileName [in],传入的char数组,大小应足以保存类似len(2018-4-16 15-46-39.wav)+1的大小
* @return 成功创建文件返回true, 否则返回true
*/
bool String2Speech::ConvertTTS(string str, char *SzFileName)
{
ISpVoice *pVoice = NULL;
if (FAILED(::CoInitialize(NULL)))
return FALSE;
HRESULT hr = CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice, (void **)&pVoice);
if (SUCCEEDED(hr))
{
CComPtr <ISpStream> cpWavStream;
CComPtr <ISpStreamFormat> cpOldStream;
CSpStreamFormat originalFmt;
pVoice->GetOutputStream(&cpOldStream);
originalFmt.AssignFormat(cpOldStream);
char SaveName[30];
// 基于当前系统的当前日期/时间
time_t now = time(0);
tm *t = localtime(&now);
sprintf_s(SaveName, "%d-%d-%d %d-%d-%d.wav", t->tm_year+1900, t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
strcpy_s(SzFileName, strlen(SaveName)+1, SaveName);
hr = SPBindToFile(SaveName, SPFM_CREATE_ALWAYS, &cpWavStream, &originalFmt.FormatId(), originalFmt.WaveFormatExPtr());
if (SUCCEEDED(hr))
{
pVoice->SetOutput(cpWavStream, TRUE);
WCHAR* w = str_to_wcharstr(str);
//use mywstring to do:
pVoice->Speak(w, SPF_IS_XML, NULL);
delete [] w;
pVoice->Release();
pVoice = NULL;
}
}
::CoUninitialize();
return true;
}
经过代码走读,类实现文件如下:
#include "stdafx.h"
#include <sapi.h>
#include <sphelper.h>
#include "tts_module.h"
using namespace std;
/** @fn bool String2Speech::ConvertTTS(const std::string& Content, const std::string& FileName)
* @brief 实现std::string转换为wav文件
* @param Content [in] 类型std::string引用,将其转换为wav文件
* @param FileName [in],类型std::string引用,内容形式为GUID.wav。
* @return 成功创建文件返回true, 否则返回true
*/
bool String2Speech::ConvertTTS(const std::string& Content, const std::string& FileName)
{
ISpVoice *pVoice = NULL;
if (FAILED(::CoInitialize(NULL)))
return false;
bool ret = true;
do
{
HRESULT hr = CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice, (void **)&pVoice);
if (FAILED(hr) || (NULL == pVoice))
{
TALKCLIENTPLUGIN_ERROR(" -CoCreateInstance Fails, errCode: %d", GetLastError());
ret = false;
break;
}
CComPtr <ISpStream> cpWavStream;
CComPtr <ISpStreamFormat> cpOldStream;
CSpStreamFormat originalFmt;
hr = pVoice->GetOutputStream(&cpOldStream);
//在没有声卡的情况下pVoice->GetOutputStream()中cpOldStream会生成空指针
//之前的代码并有对hr和cpOldStream进行非空判断,导致了程序在此处发生崩溃,因为生成了空指针
if (FAILED(hr) || (NULL == cpOldStream))
{
TALKCLIENTPLUGIN_ERROR("- GetOutputStream failed, lastError:[%d][%d]", hr, GetLastError());
ret = false;
break;
}
originalFmt.AssignFormat(cpOldStream);
hr = SPBindToFile(FileName.c_str(), SPFM_CREATE_ALWAYS, &cpWavStream, &originalFmt.FormatId(), originalFmt.WaveFormatExPtr());
if (FAILED(hr))
{
TALKCLIENTPLUGIN_ERROR("- SPBindToFile Fails, errCode: %d", GetLastError());
ret = false;
break;
}
pVoice->SetOutput(cpWavStream, TRUE);
//把文字内容转换成宽字符串进行播放,生成wav文件
std::wstring VoiceContent = CommonTools::G2W(Content.c_str());
pVoice->Speak(VoiceContent.c_str(), SPF_IS_XML, NULL);
pVoice->Release();
pVoice = NULL;
} while (0);
::CoUninitialize();
return ret;
}