您的位置:首页 > 运维架构 > Linux

中文TTS 的简单实现(基于linux)之 语音库的实现

2012-01-11 16:23 465 查看
语音库保存着常用汉字的发音(多音的汉字只记录其一种发音,这也是本系统的一个缺陷,需要以后完善),所以先要得到一汉字集,这个汉字集包含了大部分常用的汉字,然后在根据这个汉字集,来一个个的取得汉字的发音,并且按一定的规则保存到语音库中。
语音库保存着常用汉字的发音(多音的汉字只记录其一种发音,这也是本系统的一个缺陷,需要以后完善),所以先要得到一汉字集,这个汉字集包含了大部分常用的汉字,然后在根据这个汉字集,来一个个的取得汉字的发音,并且按一定的规则保存到语音库中。

所以实现语音库可以分为三步:
1.1:取得常用汉字的集合
1.2:根据汉字集,使用一些朗读软件生成该汉字集的语音文件
1.3:处理汉字集语音文件的格式,使它能符合我们的要求

1.1根据汉字编码规则获取汉字字符集的文本文件
1.1.1编码知识:

所谓编码,是以固定的顺序排列字符,并以此作为记录、存贮、传递、交换的统一内部特征。一个汉字有ASC II码、区位码等与之对应。ASC II码中对应于码值161到254的字符用于表示汉字,每个汉字用两个ASC1I码值对应的字符表示。区位码用4位数字表示,前两位从01到94称区码,后两位从01到94称位码。一个汉字的前一半是ASC II码为“160+区码”的字符,后一半是ASCII码为“160+位码”的字符。例如:“刘”的区位码是3385,其意为区码33和位码85,它是由ASCII码为160+33=193和160+85=245的两个字符组成。

该文所说的汉字字符集一般是指ISO 10646.1 即GB130o0.1。在Windows 95/98/2000中,微软提供了“汉字扩展内码规范(GBK)”以解决汉字的收字不足、简繁共存、简化代码体系间转换等汉字信息交换的瓶颈问题,利用GBK可以方便解决“镕”、“薯”等大量汉字的交换问题而不必自行造字了。GBK字库共分为5部分,其中GBK/1和GBK/5为符号部分,GBK/2为国标汉字部分,GBK/3和GBK/4为扩展汉字部分。其中,第16区至55区为一级汉字,以拼音排序,共计3755字,56—87区为二级汉字,按偏旁部首排序,共计3008字。
1.1.2程序代码:
用C++实现的获取GBK中一级汉字字符的代码段如下:
//getgbk.cpp一获取GBK汉字码文件
#include <strstream h> //字符串I/O操作
#include <fstream.h> //文件I/O操作
unsigned char oneline[4];
ofstream ofs("gbhz.txt",ios::binary );
oneline[2]=163;
oneline[3]=172;
int qm;
int wm;
for( qm=176;qm<=247;qm++) //区码0XB0—0XD7 87
for(wm=161;wm<=254;wm++) //位码0XA1—0XFE
if(!((qm==247)&&(wm=250)))
//剔除GBK中没有编码的字位
{
oneline[0]=qm; //汉字区码
oneline[1]=wm; //汉字位码
ofs.write((char *)&oneline,4); //写一行至gbhz txt

}//if end
1.2:根据取得的汉字集,使用一些报读软件生成该汉字集的语音文件,一般为WAV格式的。
这里取名为
gbhz.wav
1.3:
处理汉字集读音文件的格式
1.3.1 理解WAV文件格式
WAVE文件作为多媒体中使用的声波文件格式之一.它是以RlFF格式为标准的 每个wAVE文件的头4个字节便是
“RIFF” WAVE文件由文件头和数据体两大部分组成。其中文件头又分为RIFE/WAV文件标识段和声音数据格式说明段两部分 。WAVE文件格式说明见下表,

[align=center]内容[/align][align=center]数据类型[/align][align=center]字节数[/align]
[align=center]“RIFF”标志[/align][align=center]Char[/align][align=center]4Byte[/align]
[align=center]文件大小[/align][align=center]Long int[/align][align=center]4Byte[/align]
[align=center]“wave”标志[/align][align=center]Char[/align][align=center]4Byte[/align]
[align=center]“fmt”标志[/align][align=center]Char[/align][align=center]4Byte[/align]
[align=center]PCMWAVFORMAT数据结构大小[/align][align=center]Long int[/align][align=center]4Byte[/align]
[align=center]PCMWAVFORMAT数据结构[/align][align=center] [/align][align=center] [/align]
[align=center]“data”标志[/align][align=center]Char[/align][align=center]4Byte[/align]
[align=center]语音数据大小[/align][align=center]Long int[/align][align=center]4Byte[/align]
可以以时域-幅度的方式显示出原始声音的波形,这是最简单同时也是最直接的信息处理方式。在时域范国内,可以观察该信号波形是否连续,中间是否有祧变等。据发现,经语音引擎处理后,每个汉字所对应的语音数据长度不尽相同.这给以后截取每个汉字的语音数据造成了困难。因此.为了区分每个汉宇的语音数据.在生成汉字字符集时.在每个汉字后添加了一个逗号作为闻隔符 这样生成的语音文件的波形图(部分)如图1所示
图1:



1.3.2生成新的汉字字符集的话音文件的算法
(1)打开gbhz.wav.从gbhz.wav中读人文件头CHAR HEAD[46]。46为文件头长度。
(2)从gbhz.wav 中读入第一个汉字的语音波形数据放入CHAR BUFFER[3200]。
3200为一个汉字的语音波形数据长度.选取决于形成语音的速率、音质等因素
(3)读后面的数据,如果是0x80则不做处理.继续往后读。
ox8O是逗号语音数据,既没有发音的数据。
(4)直到读到第一个不是逗号的语音数据,开始记录第二
个汉字的语音波形数据到CHAR BUFFER[3200]
(5)重复3.4步直到读完全部的语音波形数据。

合成新的汉字字符集的语音文件后的波形图(部分)如图2所示
图2:新的语音文件波形图



1.3.3 处理代码如下
#define MAXLEN 32000
int HandingWav()
{
FILE * fpf,*fpt; //文件操作指针
if((fpf=fopen("gbhz.wav","rb+"))==NULL) //gbhz.wav为处理前的语音文件
return -1;
if((fpt=fopen("ddd.wav","rb+"))==NULL) //ddd.wav为合成的新的语音文件
return -1;

char head[46]; //wav文件的文件头长度
char data[100]; //用来加速文件处理的数组
char buffer[MAXLEN];
memset(buffer,0,MAXLEN);
fread(head,sizeof(head),1,fpf); //head of wav
fwrite(head,sizeof(head),1,fpt);
while(!feof(fpf))
{
fread(buffer,MAXLEN,1,fpf); //读一个字的发音
fwrite(buffer,MAXLEN,1,fpt); //写一个字
memset(buffer,0,MAXLEN);
fread(data,1,1,fpf); //读一个字节
while(data[0]==char(0x80)) //判断是否为0x80
{
if(fread(data,100,1,fpf)==-1) //每次取100个字节,但只判断第一个字节,这样可以加速文件处理
{
fclose(fpf);
fclose(fpt);
return -1;
} //end if
} //end while 判断是否为0x80
} // end while(!feof(fpf))

fclose(fpf); //关闭文件
fclose(fpt);
return 0;
}
经过以上的操作后,就形成了我们所要的语音库了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: