⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 psola.m

📁 语音合成PSOLA算法实现 语音合成PSOLA算法实现
💻 M
字号:
%=================================================================
%             PSOLA算法实现程序
%=================================================================
%
%具体的算法在毕业论文《基于PSOLA的汉语文语转换技术研究》P44中有详细的介绍。
%
%需要注意的问题:目前对声母(清音)还没有修改,只是修改韵母(浊音),在必要的时候可以适当加以处理声母。
%对声母的处理只能调整音长和音强,也就是复制一段接在声母后面以增长音长,乘以某个系数以提高音强。
%=================================================================
%2006年7月    郭锋    版本 1.0
%=================================================================
clear all
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%产生4个声调所对应的声调函数,数据通过对声调曲线的图像来采样获得
                                                              %实验证实:11个采样点已经可以得到实验要求。
t=0:0.1:1.0;
f1=[0.453 0.470 0.472 0.469 0.466 0.465 0.468 0.473 0.476 0.470 0.447];
f2=[0.011 0.081 0.10 0.128 0.163 0.236 0.305 0.384 0.460 0.520 0.544];
f3=[-0.185 -0.106 -0.151 -0.205 -0.2309 -0.20 -0.105 0.001 0.124 0.220 0.324];
f4=[0.463 0.531 0.504 0.438 0.363 0.267 0.184 0.120 0.046 0.001 -0.064];
f1=f1+0.6;  f2=f2+0.6;  f3=f3+0.6;  f4=f4+0.6; %往上提升0.6,把数据全部化为正数
kp1=polyfit(t,f1,4);         %拟和得到四个声调的声调函数,它的图像形式就是调型曲线,分别用kp1~kp4来标示。
kp2=polyfit(t,f2,4);
kp3=polyfit(t,f3,4);
kp4=polyfit(t,f4,4);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%产生基音变化序列
[pitch,Fs]=wavread('a.wav');                                      %读入一个基音周期,例如a的一个基音。
OriginPitchLength=length(pitch);
PithNum=40;                   %基音数目从此输入,对应着音长。
z=linspace(0,1,PithNum);      
Fn=polyval(kp4,z);            %通过调型函数来获得需要的声调序列。
Fn=1./Fn;                     %计算基频数列
KK=log(10+10.*Fn);            
scale=OriginPitchLength/KK(PithNum/2);    %scale表示单位数据代表的基音点数
ResultPitchLength=round(scale.*KK);       %获得该声调对应的基音周期序列,准备用PSOLA调整基音周期。
%以下四行注释为早期的一些实验结果,这里不用理会。
%chazhiSerial=round(PitchSerial-PitchSerial(15))    %获得插值点数序列
%测试二声的序列  最大基音和最小基音相差50个  169.6154--122.5000
%三声   最大基音和最小基音相差40个   183.7500--147
%四声   最大基音和最小基音相差60个   122.5000--183.7500
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%开始基音同步叠加,改变声调
a=pitch';
resultpitch=a;  %开始调整基音resultpitch。
reginpitch=a;   %reginpitch留作最后来和调整过的resultpitch进行比较。
K=zeros(1,PithNum);
for ii=1:PithNum
    if (OriginPitchLength==ResultPitchLength(ii))        %如果需要的基音数值NeedNum与原始基音数值OriginNum相等
        c=a;                                             %那么就不作修改,直接把原始基音a给存储变量c。
    else                                                 %否则的话,就对原始基音进行先插值再抽取。
         K(ii)=lcm(OriginPitchLength,ResultPitchLength(ii));  %K为原始基音数值,例如5,和需要的基音数值,例如7,的最小公倍数。
         D1(ii)=K(ii)/OriginPitchLength;
         D2(ii)=K(ii)/ResultPitchLength(ii);
         b=zeros(1,K(ii));
          num=1;
         %%%%%%%%%%%%%%%%%%%%%%%%%%%                     插值
         for i=1:K(ii)
           if(rem(i,D1(ii))==1)          %D1(ii)整倍,就直接赋值,不作修改
             b(i)=a(num);
             num=num+1;
           elseif (num<=OriginPitchLength) %否则,进行线性插值,扩充点数。
             b(i)=b(i-1)+(a(num)-a(num-1))/(D1(ii)-1);
           elseif (num>OriginPitchLength)
            b(i)=a(num-1);       %如果是最后一个数据点,就直接幅值,不需要再插值。
           end
         end
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  按照需要的间隔进行数据抽取
         count=1;
         c=zeros(1,ResultPitchLength(ii));
        for j=1:K(ii)
         if (rem(j,D2(ii))==0)
           c(count)=b(j);
           count=count+1;
         end
        end
    end
     reginpitch=[reginpitch a];
     resultpitch=[resultpitch c];
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%比较结果
[am,an]=size(reginpitch);
[cm,cn]=size(resultpitch);
%reginpitch=[a zeros(1,abs(cn-an))];
[qingyin,Fs]=wavread('t.wav');      %读入清音音节
%%%%%%%%%%%%%%%%%%%%%%%%%用曲线进行衰减语音波形,使得整个浊音语音波形中间音强高,首尾低,方才符合人类自然语音。
tjidian=1/100;
xjidian=0.8/65;
t0=[3 12 21 30 56 76 85 93 97];
x0=[23 32 43 41 37 33 28 22 19];
T0=tjidian.*t0;
X0=xjidian.*x0+0.2;
s1=polyfit(T0,X0,5);      %采用的衰减曲线s1为开口向下的抛物线。
%z=linspace(0,1,100);
%Fn=polyval(p1,z);
%plot(z,Fn)          %可以观测衰减曲线
k1=linspace(0,1,an);
k2=linspace(0,1,cn);
sjn1=polyval(s1,k1);   %获得原始基音对应的衰减序列。
sjn2=polyval(s1,k2);   %获得合成基音对应的衰减序列。
sum1=reginpitch.*sjn1;  %衰减原始基音序列
sum2=resultpitch.*sjn2; %衰减合成基音序列
outSpeechResult=[qingyin' sum2];
outSpeechOrign=[qingyin'  sum1];    %给outSpeechOrign乘以系数K就可以修改音强。
wavplay(outSpeechResult,Fs)         %读出合成语音
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%把结果以图形的形式显示出来。
subplot(2,1,1)
plot(outSpeechOrign)
grid on
title('汉语“他(ta1)”的时域波形图')
wavplay(outSpeechOrign,Fs)
subplot(2,1,2)
plot(outSpeechResult)
title('TD-PSOLA处理后变为“踏(ta4)”的时域波形图')
grid on

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -