情感语料库大致可以通过以下3个方法获的:(1) 从我们的现实生活中所采集的真实的自然语料,然后再经过人工挑选获得可以使用的语料;(2) 让专业或者非专业人士进行对高兴、愤怒等情感进行模仿并录制语料库;(3) 制造恰当的环境氛围来刺激那些专业或非专业人士,然后再进行语料库的录制。
这3种方法各有各的优缺点:
第一种分类方法录制的语料库几乎可以获得最接近于人的情感,但是可使用性比较差,并且很有可能涉及到一些与隐私权有关的法律问题。另外,这种自然度非常高的情感语料,即便是人类自身有时也很难辨别出它的情感分类,所以这种方法基本上还单纯处于一种理论构想的阶段。
第二种语料库收集的方法是我们经常见的,几乎所有的情感语音特征参数的提取所需要的语料库都是用这种方法录制的。这种方法有两个突出的优点:(1) 极利于操作,只需要一些简单的录音设备(一台电脑,一个麦克风),然后再找一个安静的环境进行录音就可以了;(2) 这样录制的语料很容易进行区分。但是这样录制的语料的情感只是一种模拟的情感,是录音者故意装出来的,这与真实的情感之间的差距完全取决于录音者的模仿能力。
第三种方法的可操作性也比较强,并且可以获得比使用第二种方法更为接近真实情感的情感语料库,但是这种方法没有办法确认所处的环境对录音者的刺激是否有效,以及刺激所起的作用有多大。
鉴于上述的比较我们选取了第二种方法来获得所需的情感语料库。
为了能够建立尽可能完善的语音数据采样库,我们在录音以及选择录音的语句的过程中遵循了一些原则:
(1) 进行录制的语句不能有非常明确的语义倾向性,只有这样录制的语句才能够保证建立语音库时不会影响到实验者的判断。
(2) 选择的录音的语句应能够比较容易的加入说话人的不同情感。如果所选择的语句是比较中性的或者说是很难强加一定的情感,那必然就会对发音和识别都会带来很大的困难,从而无法比较针对同样一句语句,在各种不同的情感状态下情感特征参数的不同之处。
(3) 录音者的发音时间应该控制在5秒以下,时间过长不利于情感的表达,也会引起用于情感判断的特征参数的弱化。
(4) 录制语音所选择语句中的汉语,都要用标准普通话的表达方式,不能用带有各种方言的表达形式。
(5) 所选择录制的语句尽可能避免开无声辅音,如c、p、s、t,避免这些辅音可能引起的基音周期轨迹的不连续。
(6) 所录制的语句男性和女性应该都适用。
我们在录制语音时为了避免对所用的实验语句的情感表达过于夸张,本文语音库的录制选择了非专业的说话人作为语音采样的对象。我们都以电升0602的李煜录制实验用的语音库,李煜同学的普通话标准且没有任何喉病。
进行录音的地点选在教师一间空旷的办公室中进行。录音时将门窗紧闭,保证录音较少受到外界噪音的干扰。同时尽量的保持室内的安静。所有录制的语音样本均使用标准的麦克风,采用了8000Hz,8bit的单声道音频格式录制成标准PCM编码格式的WAV文件。
当然,对于我们来说建立由数千句语音样本组成的数据库是不现实的。因此,我们对每个情感语句都按三种情感状态进行采样。说话人都按照这三种情感状态依次表达各句,且每种情感状态均重复20遍,共计180句。为了运算的简便,我们把每一种情感语句分别取10句能够明显表达情感的语句。完成采集后,实验用情感语音库共由90句语音样本组成。
在本论文中对基频的提取我们采用的是倒谱法,该方法比较容易理解,提取的基频也比较准确。该方法的是通过MATLAB7.1软件实现的。在MATLAB7.1环境下我们输入正确的程序就能完成基频特征参数的提取。为了得到基频的模板曲线,我们对3种情感状态下的句语句进行了统计平均。同时,我们使用了3点平滑处理,目的是让基频的模板曲线看起来效果更好。
提取了基频特征参数后,就将待识别的样本与模板相匹配,匹配时采用的是欧氏距离法。根据MATLAB运行的结果,列出了相应的表格,根据表格结果就可以判定语句的识别正确率了。
3.4.1 基频提取的程序实现过程
filename='C:\work\nx1.wav'
y=wavread(filename)
siz=wavread(filename,'size')
s=floor((siz-128)/128)
[xhat,nd] = CCEPS(y)
for m=1:s
mm1=(m-1)*128+1
mm2=mm1+127
n=mm1:mm2
x(n)=xhat(n)
[c1,i1]=max(x(mm1+25:mm2))
mm3=i1-25
[c2,i2]=max(x(mm1+25:mm3))
If c2>0.75.*c1
fn=i2
else
fn=i1
end
f1(1,m)=8000/fn
if f1(1,m)>400
f1(1,m)=0;
else if f1(1,m)<100
f1(1,m)=0
end
end
end
for m=2:s-1;
x1=[ f1(m-1) f1(m) f1(m+1) ];
f2(m)=median(x1);
end
3.4.2 语速提取的程序的实现过程
y=wavread(‘nx1.wav’)
siz=wavread(‘nx1.wav’,’size’)
t1=siz/8000
v1=3/t1
下面就是所提取的3种基频模板曲线和识别样本与模板匹配结果的表格。下面的语句都以“你来了”语句为例。
能量的提取我们采用的是短时能量法,其方法也是运用MATLAB7.1软件实现的。同基频特征参数一样,在对能量的处理也使用相同的情感语句采用相同的步骤,先对提取的能量参数进行统计平均,得出3种情感(高兴、悲伤和平常)的能量模板曲线,对模板曲线也使用了3点平滑处理。然后再根据待识别样本与模板的匹配得出的距离结果列出相应的表格。
下面就是就是所提取的3种基频模板曲线和识别样本与模板匹配结果的表格。
能量模板的MATLAB仿真图
图4-3 高兴状态下的能量的模板图形
图4-4 悲伤状态下的能量的模板图形
图4-6 平常状态下能量的模板图形
(1) 提取基音频率时的程序:
for m=1:s
mm1=(m-1)*128+1
mm2=mm1+127
n=mm1:mm2
x(n)=xhat(n)
[c1,i1]=max(x(mm1+25:mm2))
mm3=i1-25
[c2,i2]=max(x(mm1+25:mm3))
if c2>0.75.*c1
fn=i2
else
fn=i1
end
f10(1,m)=8000/fn
if f10(1,m)>400
f10(1,m)=0
else if f10(1,m)<100
f10(1,m)=0
end
end
end
fx=(f1+f2+f3+f4+f5+f6+f7+f8+f9+f10)/10
for m=2:s-1;
x1=[ fx(m-1) fx(m) fx(m+1) ];
fm(m)=median(x1);
end
figure();
plot(fm,'.');
title('喜的基频曲线')
(2) 提取能量时的程序:
filename='C:\work\nx1.wav'
y=wavread(filename)
siz=wavread(filename,'size')
s=floor((siz-128)/128)
N=256
ham=hamming(N)
j=1
for m=1:s
k=j+255
n=j:k
y(n)=y(n).*ham
sum=0
for n=j:k
sum=y(n).*y(n)+sum
end
en(m)=sum
j=j+128
end
figure()
plot(en)
title('喜的能量图')
(3) 提取语速时的程序:
y=wavread(‘nx1.wav’)
siz=wavread('nx1.wav',' size')
t1=siz/8000
v1=3/t1
(4) 基频的匹配程序
disp('正在进行模板匹配...') ;
sum=0;
for i=1:42
u=(fx1(i)-fx(i)).^2;
sum=sum+u
end
dxx=sqrt(sum) ;
fprintf('匹配的距离为:dxx\n');
sum=0;
for i=1:42
u=(fx1(i)-f(i)).^2;
sum=sum+u
end
dxp=sqrt(sum) ;
fprintf('匹配的距离为:dxx\n');
sum=0;
for i=1:42
u=(fx1(i)-fa(i)).^2;
sum=sum+u
end
dxa=sqrt(sum) ;
fprintf('匹配的距离为:dxa\n');
dmin=0
if dxx>dxa
dmin=dxa;
else
if dxx>dxp
dmin=dxp;
else
if dxa>dxp
dmin=dxp
end
end
end
if dmin==0
fprintf('基频的匹配结果正确')
else
fprintf('基频的匹配结果错误')
end
(5) 能量的匹配程序
disp('正在进行模板匹配...') ;
sum=0;
for i=1:42
u=(enx1(i)-enx(i)).^2;
sum=sum+u
end
dxx=sqrt(sum) ;
fprintf('匹配的距离为:dxx\n');
sum=0;
for i=1:42
u=(enx1(i)-en(i)).^2;
sum=sum+u
end
dxp=sqrt(sum) ;
fprintf('匹配的距离为:dxx\n');
sum=0;
for i=1:42
u=(enx1(i)-ena(i)).^2;
sum=sum+u
end
dxa=sqrt(sum) ;
fprintf('匹配的距离为:dxa\n');
dmin=0
if dxx>dxa
dmin=dxa;
else
if dxx>dxp
dmin=dxp;
else
if dxa>dxp
dmin=dxp
end
end
end
if dmin==0
fprintf('能量的匹配结果正确')
else
fprintf('能量的匹配结果错误')
end