您的位置:首页 > 其它

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);

}

===========转载请注明出处:南才北往==============

===本文由所有代码全由南才北往


开发的转载请注明原作者名称===

===========转载请注明出处:南才北往==============

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: