TTS中英文混合朗读的完全设计实现
2009-10-01 20:59
267 查看
===========转载请注明出处:南才北往==============
===本文由所有代码全由南才北往
开发的转载请注明原作者名称===
===========转载请注明出处:南才北往==============
中英文混合朗读一直是个难点
,即在一段文本中要将中文和英文分离出来进行分别朗读,又不能打乱朗读的次序,所以我们设计如下的两种方法,每种方法都有各自的优点和缺点。
①采用同步朗读方式进行混合朗读
:
将朗读文本进行提取分析,提取本文本中的中文和英文,在编程中,我们设定两个
标志:
const int
IsEnglish = 0;
// 英文标志
const int
IsChinese = 3;
// 中文标志
标点符号和数字默认和它前面的字的标志一致。当处理文本时标志发生改变时,
立即调用语音合成引擎进行朗读。
//循环遍历每个字
for
(int i = 0; i < length; i++)
{
//提取字母
current = m_strTxt.GetAt(i);
// 如果是英文字母
,
标志设为
0
if
((current >= 'A' && current <= 'Z') || (current >= 'a' &&
current <= 'z'))
{
CFlag = IsEnglish;
// 如果是英文字母
,
标志设为
0
}
else if
((current >=0&¤t<= 64)||(current >=91&&
current<= 96)||(current >=123&¤t<= 127))
//如果是数字则和它的前一个字母的标志一样
{
if
(PFlag==IsEnglish)
CFlag=IsEnglish;
//英文标志
else
CFlag=IsChinese;
//中文标志
}
else
{
CFlag = IsChinese;
//中文标志
}
if
(CFlag == PFlag)
//若当前标志与前一个字母标志相同则个数增一
iCount++;
else
{
if
(iCount!=0)
//字符类型变化
,
读出前面的文本
{
if
(PFlag==IsEnglish)
SetVoice(szwEnglish);
//将引擎设置成英文引擎
else
SetVoice(szwChinese);
//将引擎设置成中文引擎
str = m_strTxt.Mid(first,iCount);
//提取出标志相同的文字
//设置成同步朗读方式,将文本同步朗读出来
hr = m_IpVoice->Speak(str.AllocSysString(), 0, 0 );
}
PFlag = CFlag;
//改变当前标志
first = i;
//设置当前位置
iCount = 1;
//个数还原为
1
}
}
//读出最后一段文本
if
(PFlag==IsEnglish)
SetVoice(szwEnglish);
//将引擎设置成英文引擎
else
SetVoice(szwChinese);
//将引擎设置成中文引擎
str = m_strTxt.Mid(first,length);
//设置成同步朗读方式,将文本同步朗读出来
hr = m_IpVoice->Speak(str.AllocSysString(), 0, 0 );
===========转载请注明出处:南才北往==============
===本文由所有代码全由南才北往
开发的转载请注明原作者名称===
===========转载请注明出处:南才北往==============
②
采用异步XML格式进行混合朗读
:
将第二种方式与第一中方式相似,区别只是在于它是将文本进一步进行处理,最后生成符合XML朗读格式的文本后对文本进行朗读,而不是调用当标志发生改变时立即调用语音合成引擎进行朗读:
//设置XML起始标志
strEngine.printf("
<xml version=/"1.0/">/n<SAPI>/n
<VOICE REQUIRED=/"NAME=%s/">
",m_strZHEngine.c_str());
strWord+=strEngine;
for
(
int
i = 1; i <= nLength; i++)
{
......
if
(iCount!=0)
//字符类型变化
,
进行文本处理
{
if
(PFlag==IsChinese)
//中文标志
{
//将中文朗读文本
XML
格式插入文本中
strWord+="
</VOICE>/n
";
strEngine.printf("
<VOICE REQUIRED=/"NAME=%s/">
",m_strZHEngine.c_str());
strWord+=strEngine;
strWord+=strTemp.SubString(first,iCount);
}
else
{
//将英文朗读文本
XML
格式插入文本中
strWord+="
</VOICE>/n
";
strEngine.printf(
"
<VOICE REQUIRED=/"NAME=%s/">
",m_strENEngine.c_str());
strWord+=strEngine;
strWord+=strTemp.SubString(first,iCount);
}
}
......
}
//读出最后一段文本
if
(PFlag==IsChinese)
{
strWord+="</VOICE>/n";
strEngine.printf("
<VOICE REQUIRED=/"NAME=%s/">
",m_strZHEngine.c_str());
strWord+=strEngine;
strWord+=strTemp.SubString(first,iCount);
//添加
xml
结束标志
strEngine="
</VOICE>/n</SAPI>/n</xml>
";
strWord+=strEngine;
}
else
{
//将英文朗读文本
XML
格式插入文本中
strWord+="
</VOICE>/n
";
strEngine.printf("
<VOICE REQUIRED=/"NAME=%s/">
",m_strENEngine.c_str());
strWord+=strEngine;
strWord+=strTemp.SubString(first,iCount);
//添加
xml
结束标志
strEngine="
</VOICE>/n</SAPI>/n</xml>
";
strWord+=strEngine;
}
//采用
XML
和异步朗读方式朗读文本
TTS_Speak(strWord.c_str(),IS_MIX_SPEECH|IS_ASY_SPEECH);
}
当然上面的两种方式各有各的优缺点,第一种方式处理较快,但是不能进行异步朗读,同步朗读时不能进行其它操作,而且频繁调用语音引擎进行声音设置容易造成内存占有率较高。第二种方法需要对文本进行插入处理比较耗时,且要求开发者要对XML语音朗读格式有一定的了解所以开发比较复杂,但它是可以进行异步朗读,使你在朗读的时候还能进行其他操作,且采用XML朗读方式,使你不用人为的去改变引擎的声音,将操作交给系统进行处理摆脱了频繁改变声音后造成的内存占有率较高的问题!
具体源码如下:
===========转载请注明出处:南才北往==============
===本文由所有代码全由南才北往
开发的转载请注明原作者名称===
===========转载请注明出处:南才北往==============
①采用VC开发的:
////////////////////////////////////////////////////////////////////////////////////////////
//函数 名:HRESULT CText2Speech::MixSpeech(char *speech)
//编写 者:南才北往
//参考资料: Speech SDK5.1 帮助文档
//函数功能:语音合成朗读--混合朗读.
//输入参数:char* speech - 文本朗读内容
//返回 值:S_OK - 成功 ; E_FAIL -失败
//备 注: 无
///////////////////////////////////////////////////////////////////////////////////////////
HRESULT CText2Speech::MixSpeech(char
*speech)
{
long
length;
HRESULT hr;
CString m_strTxt=speech,str;
char
current;
int
PFlag, CFlag;
int
iCount, first;
const int
IsEnglish = 0; // 英文标志
const int
IsChinese = 3; // 中文标志
length = m_strTxt.GetLength();
PFlag = IsChinese;
iCount=0;
first=0;
for
(int
i = 0; i < length; i++)
{
current = m_strTxt.GetAt(i);
if
((current >= 'A' && current <= 'Z') || (current >= 'a' && current <= 'z'))
{
CFlag = IsEnglish; // 如果是英文字母,标志设为0
}
else if
((current >=0&¤t<= 64)||(current >=91&¤t<= 96)||(current >=123&¤t<= 127))//如果是数字则和它的前一个字母的标志一样
{
if
(PFlag==IsEnglish)
CFlag=IsEnglish;
else
CFlag=IsChinese;
}
else
{
CFlag = IsChinese;
}
if
(CFlag == PFlag)
iCount++;
else
{
if
(iCount!=0) //字符类型变化,读出前面的文本
{
if(PFlag==IsEnglish)
SetVoice(szwEnglish);
else
SetVoice(szwChinese);
str = m_strTxt.Mid(first,iCount);
hr = m_IpVoice->Speak(str.AllocSysString(), 0, 0 );
}
PFlag = CFlag;
first = i;
iCount = 1;
}
}
//读出最后一段文本
if
(PFlag==IsEnglish)
SetVoice(szwEnglish);
else
SetVoice(szwChinese);
str = m_strTxt.Mid(first,length);
hr = m_IpVoice->Speak(str.AllocSysString(), 0, 0 );
return
hr;
}
②采用c++builder开发的
===========转载请注明出处:南才北往==============
===本文由所有代码全由南才北往
开发的转载请注明原作者名称===
===========转载请注明出处:南才北往==============
////////////////////////////////////////////////////////////////////////////////////////////
//函数 名:
void __fastcall TForm1::MixSpeech()
//编写 者:南才北往
//参考资料: Speech SDK5.1 帮助文档
//函数功能:语音合成朗读--混合朗读.
//输入参数:
Edit1->Text
- 文本朗读内容
//返回 值:无
//备 注: 无
///////////////////////////////////////////////////////////////////////////////////////////
void __fastcall
TForm1::MixSpeech()
{
int
nLength;
char
chCurrent;
AnsiString strTemp,strWord;
AnsiString strEngine;
//语音引擎名称
strTemp=Edit1->Text;
nLength=strTemp.Length();
int
PFlag, CFlag;
int
iCount, first;
const int
IsEnglish = 0; // 英文标志
const int
IsChinese = 3; // 中文标志
PFlag = IsChinese;
iCount=0;
first=1;
strEngine.printf("<xml version=/"1.0/">/n<SAPI>/n<VOICE REQUIRED=/"NAME=%s/">
",m_strZHEngine.c_str());
strWord+=strEngine;
for (int i = 1; i <= nLength; i++)
{
chCurrent=strTemp.operator [](i);
if((chCurrent >= 'A' && chCurrent <= 'Z') || (chCurrent >= 'a' && chCurrent <= 'z'))
{
CFlag = IsEnglish; // 如果是英文字母,标志设为0
}
else if((chCurrent >=0&&chCurrent<= 64)||
(chCurrent >=91&&chCurrent<= 96)||
(chCurrent >=123&&chCurrent< 127))//如果是数字则和它的前一个字母的标志一样
{
if(PFlag==IsEnglish)
CFlag=IsEnglish;
else
CFlag=IsChinese;
}
else
{
CFlag = IsChinese;
}
if (CFlag == PFlag)
iCount++;
else
{
if (iCount!=0) //字符类型变化,读出前面的文本
{
if(PFlag==IsChinese)
{
strWord+="</VOICE>/n
";
strEngine.printf("<VOICE REQUIRED=/"NAME=%s/">
",m_strZHEngine.c_str());
strWord+=strEngine;
strWord+=strTemp.SubString(first,iCount);
}
else
{
strWord+="</VOICE>/n
";
strEngine.printf("<VOICE REQUIRED=/"NAME=%s/">
",m_strENEngine.c_str());
strWord+=strEngine;
strWord+=strTemp.SubString(first,iCount);
}
}
PFlag = CFlag;
first = i;
iCount = 1;
}
}
//读出最后一段文本
if(PFlag==IsChinese)
{
strWord+="</VOICE>/n
";
strEngine.printf("<VOICE REQUIRED=/"NAME=%s/">
",m_strZHEngine.c_str());
strWord+=strEngine;
strWord+=strTemp.SubString(first,iCount);
strEngine="</VOICE>/n</SAPI>/n</xml>
";
strWord+=strEngine;
}
else
{
strWord+="</VOICE>/n
";
strEngine.printf("<VOICE REQUIRED=/"NAME=%s/">
",m_strENEngine.c_str());
strWord+=strEngine;
strWord+=strTemp.SubString(first,iCount);
strEngine="</VOICE>/n</SAPI>/n</xml>
";
strWord+=strEngine;
}
TTS_Speak(strWord.c_str(),IS_XML_SPEECH|IS_ASY_SPEECH);
//ShowMessage(strWord);
}
===========转载请注明出处:南才北往==============
===本文由所有代码全由南才北往
开发的转载请注明原作者名称===
===========转载请注明出处:南才北往==============
===本文由所有代码全由南才北往
开发的转载请注明原作者名称===
===========转载请注明出处:南才北往==============
中英文混合朗读一直是个难点
,即在一段文本中要将中文和英文分离出来进行分别朗读,又不能打乱朗读的次序,所以我们设计如下的两种方法,每种方法都有各自的优点和缺点。
①采用同步朗读方式进行混合朗读
:
将朗读文本进行提取分析,提取本文本中的中文和英文,在编程中,我们设定两个
标志:
const int
IsEnglish = 0;
// 英文标志
const int
IsChinese = 3;
// 中文标志
标点符号和数字默认和它前面的字的标志一致。当处理文本时标志发生改变时,
立即调用语音合成引擎进行朗读。
//循环遍历每个字
for
(int i = 0; i < length; i++)
{
//提取字母
current = m_strTxt.GetAt(i);
// 如果是英文字母
,
标志设为
0
if
((current >= 'A' && current <= 'Z') || (current >= 'a' &&
current <= 'z'))
{
CFlag = IsEnglish;
// 如果是英文字母
,
标志设为
0
}
else if
((current >=0&¤t<= 64)||(current >=91&&
current<= 96)||(current >=123&¤t<= 127))
//如果是数字则和它的前一个字母的标志一样
{
if
(PFlag==IsEnglish)
CFlag=IsEnglish;
//英文标志
else
CFlag=IsChinese;
//中文标志
}
else
{
CFlag = IsChinese;
//中文标志
}
if
(CFlag == PFlag)
//若当前标志与前一个字母标志相同则个数增一
iCount++;
else
{
if
(iCount!=0)
//字符类型变化
,
读出前面的文本
{
if
(PFlag==IsEnglish)
SetVoice(szwEnglish);
//将引擎设置成英文引擎
else
SetVoice(szwChinese);
//将引擎设置成中文引擎
str = m_strTxt.Mid(first,iCount);
//提取出标志相同的文字
//设置成同步朗读方式,将文本同步朗读出来
hr = m_IpVoice->Speak(str.AllocSysString(), 0, 0 );
}
PFlag = CFlag;
//改变当前标志
first = i;
//设置当前位置
iCount = 1;
//个数还原为
1
}
}
//读出最后一段文本
if
(PFlag==IsEnglish)
SetVoice(szwEnglish);
//将引擎设置成英文引擎
else
SetVoice(szwChinese);
//将引擎设置成中文引擎
str = m_strTxt.Mid(first,length);
//设置成同步朗读方式,将文本同步朗读出来
hr = m_IpVoice->Speak(str.AllocSysString(), 0, 0 );
===========转载请注明出处:南才北往==============
===本文由所有代码全由南才北往
开发的转载请注明原作者名称===
===========转载请注明出处:南才北往==============
②
采用异步XML格式进行混合朗读
:
将第二种方式与第一中方式相似,区别只是在于它是将文本进一步进行处理,最后生成符合XML朗读格式的文本后对文本进行朗读,而不是调用当标志发生改变时立即调用语音合成引擎进行朗读:
//设置XML起始标志
strEngine.printf("
<xml version=/"1.0/">/n<SAPI>/n
<VOICE REQUIRED=/"NAME=%s/">
",m_strZHEngine.c_str());
strWord+=strEngine;
for
(
int
i = 1; i <= nLength; i++)
{
......
if
(iCount!=0)
//字符类型变化
,
进行文本处理
{
if
(PFlag==IsChinese)
//中文标志
{
//将中文朗读文本
XML
格式插入文本中
strWord+="
</VOICE>/n
";
strEngine.printf("
<VOICE REQUIRED=/"NAME=%s/">
",m_strZHEngine.c_str());
strWord+=strEngine;
strWord+=strTemp.SubString(first,iCount);
}
else
{
//将英文朗读文本
XML
格式插入文本中
strWord+="
</VOICE>/n
";
strEngine.printf(
"
<VOICE REQUIRED=/"NAME=%s/">
",m_strENEngine.c_str());
strWord+=strEngine;
strWord+=strTemp.SubString(first,iCount);
}
}
......
}
//读出最后一段文本
if
(PFlag==IsChinese)
{
strWord+="</VOICE>/n";
strEngine.printf("
<VOICE REQUIRED=/"NAME=%s/">
",m_strZHEngine.c_str());
strWord+=strEngine;
strWord+=strTemp.SubString(first,iCount);
//添加
xml
结束标志
strEngine="
</VOICE>/n</SAPI>/n</xml>
";
strWord+=strEngine;
}
else
{
//将英文朗读文本
XML
格式插入文本中
strWord+="
</VOICE>/n
";
strEngine.printf("
<VOICE REQUIRED=/"NAME=%s/">
",m_strENEngine.c_str());
strWord+=strEngine;
strWord+=strTemp.SubString(first,iCount);
//添加
xml
结束标志
strEngine="
</VOICE>/n</SAPI>/n</xml>
";
strWord+=strEngine;
}
//采用
XML
和异步朗读方式朗读文本
TTS_Speak(strWord.c_str(),IS_MIX_SPEECH|IS_ASY_SPEECH);
}
当然上面的两种方式各有各的优缺点,第一种方式处理较快,但是不能进行异步朗读,同步朗读时不能进行其它操作,而且频繁调用语音引擎进行声音设置容易造成内存占有率较高。第二种方法需要对文本进行插入处理比较耗时,且要求开发者要对XML语音朗读格式有一定的了解所以开发比较复杂,但它是可以进行异步朗读,使你在朗读的时候还能进行其他操作,且采用XML朗读方式,使你不用人为的去改变引擎的声音,将操作交给系统进行处理摆脱了频繁改变声音后造成的内存占有率较高的问题!
具体源码如下:
===========转载请注明出处:南才北往==============
===本文由所有代码全由南才北往
开发的转载请注明原作者名称===
===========转载请注明出处:南才北往==============
①采用VC开发的:
////////////////////////////////////////////////////////////////////////////////////////////
//函数 名:HRESULT CText2Speech::MixSpeech(char *speech)
//编写 者:南才北往
//参考资料: Speech SDK5.1 帮助文档
//函数功能:语音合成朗读--混合朗读.
//输入参数:char* speech - 文本朗读内容
//返回 值:S_OK - 成功 ; E_FAIL -失败
//备 注: 无
///////////////////////////////////////////////////////////////////////////////////////////
HRESULT CText2Speech::MixSpeech(char
*speech)
{
long
length;
HRESULT hr;
CString m_strTxt=speech,str;
char
current;
int
PFlag, CFlag;
int
iCount, first;
const int
IsEnglish = 0; // 英文标志
const int
IsChinese = 3; // 中文标志
length = m_strTxt.GetLength();
PFlag = IsChinese;
iCount=0;
first=0;
for
(int
i = 0; i < length; i++)
{
current = m_strTxt.GetAt(i);
if
((current >= 'A' && current <= 'Z') || (current >= 'a' && current <= 'z'))
{
CFlag = IsEnglish; // 如果是英文字母,标志设为0
}
else if
((current >=0&¤t<= 64)||(current >=91&¤t<= 96)||(current >=123&¤t<= 127))//如果是数字则和它的前一个字母的标志一样
{
if
(PFlag==IsEnglish)
CFlag=IsEnglish;
else
CFlag=IsChinese;
}
else
{
CFlag = IsChinese;
}
if
(CFlag == PFlag)
iCount++;
else
{
if
(iCount!=0) //字符类型变化,读出前面的文本
{
if(PFlag==IsEnglish)
SetVoice(szwEnglish);
else
SetVoice(szwChinese);
str = m_strTxt.Mid(first,iCount);
hr = m_IpVoice->Speak(str.AllocSysString(), 0, 0 );
}
PFlag = CFlag;
first = i;
iCount = 1;
}
}
//读出最后一段文本
if
(PFlag==IsEnglish)
SetVoice(szwEnglish);
else
SetVoice(szwChinese);
str = m_strTxt.Mid(first,length);
hr = m_IpVoice->Speak(str.AllocSysString(), 0, 0 );
return
hr;
}
②采用c++builder开发的
===========转载请注明出处:南才北往==============
===本文由所有代码全由南才北往
开发的转载请注明原作者名称===
===========转载请注明出处:南才北往==============
////////////////////////////////////////////////////////////////////////////////////////////
//函数 名:
void __fastcall TForm1::MixSpeech()
//编写 者:南才北往
//参考资料: Speech SDK5.1 帮助文档
//函数功能:语音合成朗读--混合朗读.
//输入参数:
Edit1->Text
- 文本朗读内容
//返回 值:无
//备 注: 无
///////////////////////////////////////////////////////////////////////////////////////////
void __fastcall
TForm1::MixSpeech()
{
int
nLength;
char
chCurrent;
AnsiString strTemp,strWord;
AnsiString strEngine;
//语音引擎名称
strTemp=Edit1->Text;
nLength=strTemp.Length();
int
PFlag, CFlag;
int
iCount, first;
const int
IsEnglish = 0; // 英文标志
const int
IsChinese = 3; // 中文标志
PFlag = IsChinese;
iCount=0;
first=1;
strEngine.printf("<xml version=/"1.0/">/n<SAPI>/n<VOICE REQUIRED=/"NAME=%s/">
",m_strZHEngine.c_str());
strWord+=strEngine;
for (int i = 1; i <= nLength; i++)
{
chCurrent=strTemp.operator [](i);
if((chCurrent >= 'A' && chCurrent <= 'Z') || (chCurrent >= 'a' && chCurrent <= 'z'))
{
CFlag = IsEnglish; // 如果是英文字母,标志设为0
}
else if((chCurrent >=0&&chCurrent<= 64)||
(chCurrent >=91&&chCurrent<= 96)||
(chCurrent >=123&&chCurrent< 127))//如果是数字则和它的前一个字母的标志一样
{
if(PFlag==IsEnglish)
CFlag=IsEnglish;
else
CFlag=IsChinese;
}
else
{
CFlag = IsChinese;
}
if (CFlag == PFlag)
iCount++;
else
{
if (iCount!=0) //字符类型变化,读出前面的文本
{
if(PFlag==IsChinese)
{
strWord+="</VOICE>/n
";
strEngine.printf("<VOICE REQUIRED=/"NAME=%s/">
",m_strZHEngine.c_str());
strWord+=strEngine;
strWord+=strTemp.SubString(first,iCount);
}
else
{
strWord+="</VOICE>/n
";
strEngine.printf("<VOICE REQUIRED=/"NAME=%s/">
",m_strENEngine.c_str());
strWord+=strEngine;
strWord+=strTemp.SubString(first,iCount);
}
}
PFlag = CFlag;
first = i;
iCount = 1;
}
}
//读出最后一段文本
if(PFlag==IsChinese)
{
strWord+="</VOICE>/n
";
strEngine.printf("<VOICE REQUIRED=/"NAME=%s/">
",m_strZHEngine.c_str());
strWord+=strEngine;
strWord+=strTemp.SubString(first,iCount);
strEngine="</VOICE>/n</SAPI>/n</xml>
";
strWord+=strEngine;
}
else
{
strWord+="</VOICE>/n
";
strEngine.printf("<VOICE REQUIRED=/"NAME=%s/">
",m_strENEngine.c_str());
strWord+=strEngine;
strWord+=strTemp.SubString(first,iCount);
strEngine="</VOICE>/n</SAPI>/n</xml>
";
strWord+=strEngine;
}
TTS_Speak(strWord.c_str(),IS_XML_SPEECH|IS_ASY_SPEECH);
//ShowMessage(strWord);
}
===========转载请注明出处:南才北往==============
===本文由所有代码全由南才北往
开发的转载请注明原作者名称===
===========转载请注明出处:南才北往==============
相关文章推荐
- 使用VB.net 创建简单的TTS中英文混合语音朗读
- 使用VB.net 创建简单的TTS中英文混合语音朗读
- .net实现简单语音朗读(TTS)功能
- 中国象棋程序的设计与实现(十二)--棋盘绘制算法(尽管注释非常详细,完全理解仍有难度)
- Horspool 算法C++11实现(支持中英文混合搜索)
- 【VC++技术杂谈004】使用微软TTS语音引擎实现文本朗读
- 调用 Windows 7 中英文混合朗读
- TTS实现文字语音朗读
- Android 通过手说tts中文语音包实现中文朗读
- C#WPF 语音开发教程 TTS中英文语音(男女声音)朗读 源代码下载 csdn tts(text to sound) 一步一步 教你制作语音软件 附图和源代码
- 实现中英文混合字符串的格式化
- C#语音朗读文本 — TTS的实现
- 中国象棋程序的设计与实现(十二)--棋盘绘制算法(尽管注释非常详细,完全理解仍有难度)
- C#实现 获取指定字节长度 中英文混合字符串 的方法
- 【转】VC用TTS实现文字语音朗读
- C#实现 获取指定字节长度 中英文混合字符串 的方法
- 完全用CSS实现的中英文双语导航菜单
- C#实现 获取指定字节长度 中英文混合字符串 的方法
- Android自动朗读(TTS)的实现
- 基于Speech SDK开发中英文混合朗读程序