1、 基于 MATLAB算法的数字变声器 洗手 【摘要】 变声器的原理是通过改变输入声音频率 , 吃饭 进行改变声音的音色 、 beef音调 , 吃饭 使输出声音在感官上与原声音不同 。 洗手 变声器是借助对声音音色和音调的双重复合改变 , 吃饭 实现输出声音的改变 。 洗手 通过自己发声 , 吃饭 共振峰频率的改变是基于重采样实现的 。 洗手 同时用 LPC倒谱分析法分析共振峰的范围 , 吃饭 通过 MATLAB编写程序并构置 GUI界面 。 洗手 实验中 通过 MATLAB软件对采集来的语言信号进行频谱分析 , 吃饭 讨论不同人之间的噪音源参数和共振峰参数 , 吃饭 通过对不同人语言信号频率和
2、幅度的改变来实现不同人之间的语音转换 。 洗手 洗手 【关键词】 短时自相关法 ; b eef LPC倒谱 ; b eef 语音信号 ; b eef matlab GUI; b eef洗手 1引言 洗手 随着生活水平的提高 , 吃饭 科技的不断进步 , 吃饭 很多人为了娱乐 , 吃饭 从而希望改变自己的声音 ; beef还有如今的许多的访问节目为了保护被访问者 , 吃饭 都对声音进行了相应的处理 。 洗手 本设计通过编写matlab程序 , 吃饭 借助对声音音色和音调的双重复合改变 , 吃饭 实现输出声音的改变 。 洗手 共振峰频率的改变是基于重采样实现的 , 吃饭 从重采样原理知道 , 吃饭
3、 这也同时印发了基频的变化 ,吃饭 为保证基频变化和共振峰频率变化的独立 、 beef互不相关 , 吃饭 在基频移动时必须考虑抵消重采样带来的偏移 , 吃饭 理论上只要基频检测足够精确 , 吃饭 确实可以保证基频改变和共振峰频率改变间的互不相关 。 洗手 保证变声效果的自然度主要是没有采用基因检测将基因移动和共振峰变化彻底隔离的缘故 。 洗手 洗手 本次课程设计就是运用我们所学到的理论知识 , 吃饭 用 MATLAB软件来实现对语音信号的变声处理 , 吃饭 理论联系实际 , 吃饭 从而更好地掌握以及运用所学习的知识 。 洗手 洗手 2数字变声器的原理与算法 洗手 2.1基本原理 洗手 语音科学
4、家将人类发声过程视作一个由声门源输送的气流经以声道 、 beef口 、 beef鼻腔组成的滤波器调制而成的 。 洗手 人类语音可分为有声语音和无声语音 , 吃饭 前者是由声带振动激励的脉冲信号经声腔调制变成不同的音 , 吃饭 它是人类语言中元音的基础 , 吃饭 声带振动的频率称为基频 。 洗手 无声语音则是声带保持开启状态 , 吃饭 禁止振动引发的 。 洗手 一般来说 , 吃饭 由声门振动决定的基频跟说话人的性别特征有关 , 吃饭 如下表 , 吃饭 而无声语音则没有体现这个特征 。 洗手 说话人的个性化音色和语音的另外一个声学参数 共振峰频率的分布有关 。 洗手 儿童由于声道短 , 吃饭 其共
5、振峰频率高于成年人 , 吃饭 成年女性的声道一般短于成年男性 , 吃饭 所以女性的共振峰频率一般高于男性 。 洗手 洗手 在进行性别变声时 , 吃饭 主要考虑基音周期 、 beef基频和共振峰频率的变化 。 洗手 其中男生 、 beef女生和童声的基频 、 b eef共振峰的关系如图 1所示 ; beef基音周期改变时 , 吃饭 基频 、 beef共振峰同时变化 , 吃饭 若伸展既有男变女 、 b eef女变童 , 吃饭 反之亦可 。 洗手 本实验是基于 打开一种 声音进行相关参数提取 , 吃饭 修改 洗手 接近于女声 、 b eef男声 或童声 , 吃饭 实现声音的变换 。 洗手洗手 洗手
6、洗手 洗手 图 1 人群基频与共振峰的关系 2.2实现过程及算法 洗手 采用线性预测参数合成法 。 洗手 线性预测参数合成法利用 LPC语音分析方法 , 吃饭 通过分析自然语音样本 , 吃饭 计算出 LPC系数 , 吃饭 就可以建立信号产生模型 , 吃饭 从而合成出语音 。 洗手 大致流程如图 2所示 。洗手 洗手 洗手 洗手 洗手 洗手 洗手 洗手 洗手 洗手 洗手 洗手 2.2.1基于短时自相关法的基音周期估值 洗手 对语言信号进行低通滤波 , 吃饭 然后进行自相关计算 。 洗手 在低通滤波时 , 吃饭 采用巴特沃斯滤波器 。 洗手 洗手 根据人的说话特征设定相应指标参数 , 吃饭 对本段
7、语音设计算出巴特沃斯模拟滤波器的阶数 N为 5,吃饭 3dB截止频率 c, c = (100.1ap 1)12n,算出 c为 0.175,吃饭 归一化低通原型系统函数为 : beef洗手 Ga( p) = 1p5+b4p4+b3p3+b2p2+b1p+b0洗手 其中 b0 = 1.0000,b1 = 3.2361,b2 = 5.2361,b3 = 5.2361,b4 = 3.2361洗手 将 p = s/ 带人 Ga( p) 中 , 吃饭 得到低通滤波器 , 吃饭 洗手 Hs = c5s5+b4 c2s4+b2 c3s2+b1 c4s+b0 c5 洗手 根据设定的滤波器编写 matlab程序
8、, 吃饭 当信号经过低通滤波器后 , 吃饭 对原始信号滤波产生结果如下图 2所示 , 吃饭 低通滤波后 , 吃饭 保留基音频率 , 吃饭 然后再用 8kHz采样频率进行采样 , 吃饭 采样序列为 x(n),吃饭 然后进行下一步的自相关计算 。 洗手 洗手 洗手 洗手 洗手 洗手 洗手 洗手 2.2.2语音信号的短时自相关函数 洗手 定义语音信号自相关函数如下 : b eef洗手 Rn(k)= xn(n)xn(n+ k)n=kn1n=0 洗手 图 3 原始信号低通滤波 图 2 制作流程 其中 k为信号延迟点数 : xn(n)为语音信号 ; beefN为语音帧长度 。 洗手 经过低通滤波之后 ,吃
9、饭 取 160个样点数 , 吃饭 帧长取 10ms, 吃饭 对每帧语音求短时自相关 , 吃饭 取得自相关最大点数 ,吃饭 自相关函数在基音周期处表现为峰值 , 吃饭 这些峰值点之间的间隔的平均值就是基音周期 。 洗手 洗手 洗手 2.2.3 LPC倒谱法提取共振峰 洗手 通过线性预测分析得到合成滤波器的 系统函数为 洗手 H(Z)= 11 aizipi=1洗手 其冲击响应为 h(n),ai为预测系数 。 洗手 然后求 h(n)的倒谱 h (n),首先根据同态分析方法 , 吃饭有 H (z)=logH(z),因为 H( z)是最小相位的 , 吃饭 即在单位圆内是解析的 , 吃饭 所以 H (z)
10、可以展开成级数形式 , 吃饭 即 (z)= h (n)znn=1 ,也就是说 (z)的逆变换 (n)是存在的 , 吃饭 设(n)=0, 吃饭 将等式两端分别对 z1求导 , 吃饭 得到 : beef洗手 nh (n)n=1 zn+1= u izi+1pi=11 aizipi=1 洗手 有( 1- aizipi=1 ) n (n)n=1 zn+1= u izi+1n=1 , 令式左右两边 Z的各次幂前系数分别相等得到 : b eef洗手 (1)=1洗手 (n)=an+ (1 in)ai (n i)n1i=1 1 n p洗手 (n)= (1 in)aih (n i)n1i=1 np洗手 在本实验中
11、 , 吃饭 取预测阶数为 10, 吃饭 语音的样点数为 160, 吃饭 按照上式可直接从预测系数 ai求得倒谱 (n), 吃饭 这个倒谱是根据线性预测模型得到 , 吃饭 即称为 LPC倒谱 。 洗手 洗手 2.2.4线性预测语音信号合成 洗手 根据线性预测的基本思想 , 吃饭 用过去 M个样点值来预测现在或未来的样点值 : beef洗手 y ( n) = aiy(n i)Mi=1 洗手 y ( n)是预测信号 , 吃饭 ai为预测系数 , 吃饭 y(n)为取样信号 , 吃饭 预测误差 ( n) :洗手 E 2(n) =E y(n) aiy(n i)Mi=1 2 洗手 为使 E 2(n)最小 ,
12、 吃饭 对 ai求偏导 , 吃饭 并令其为零 , 吃饭 有 : beef洗手 E y(n) aiy(n i)Mi=1 y(n- ) =0 =1, ,M洗手 上式表明采用最佳预测系数时 , 吃饭 预测误差与过去的样点值正交 。 洗手 由于语音信号的短时平稳性 ,吃饭 要分帧处理 , 吃饭 对于每一个样点值记为 yn(n) , yn(n+N-1), 吃饭 这段语音记为 Yn。 洗手 洗手 对于语音段 Yn, 吃饭 并记 n(j,i)=E yn(m j)ym(m i) ,对于语音段 Yn, 吃饭 它的自相关函数为 :b eef洗手 H H h hhhh hhhRn(j)= yn(m)yn(m j)n
13、1m=j n=1, ,M洗手 根据 Yule walker方程 , 吃饭 可以解出样值 , 吃饭 用这种方法定期地改变激励参数 u(n)和预测系数 ai, 吃饭并使用修改过后的基因周期和共振峰参数 , 吃饭 就能合成出语音 , 吃饭 合成语音样本如下 : beef洗手 S( n) = ais(n i)pi=1 +Gu(n)洗手 ai为预测系数 ; b eefG为模型增益 ; beefu(n)为激励 ; beef合成样本 s(n); beefp为预测器阶数 ; beef洗手 洗手 2.2.5流程图 洗手 洗手 洗手 洗手 洗手 洗手 洗手 洗手 洗手 洗手 洗手 洗手 洗手 洗手 洗手 洗手 洗
14、手 洗手 洗手 洗手 洗手 洗手 洗手 洗手 洗手 洗手 洗手 洗手 洗手 洗手 洗手 洗手 3数字变声器的软件实现及仿真结果 洗手 3.1 界面设计 洗手 在设计数字变声器的界面时 , 吃饭 使用了 MATLAB提供的可视化的界面环境 Guide。 洗手 相比 通 洗手 过编写程序进行 GUI的设计 , 吃饭 可视化的界面环境更加方便快捷 。 洗手 见图 4洗手 开始 导入语音数据 S 算法 数据归一化 建立滤波器重建语言 合成并加窗 确定帧数 线性 预测法预测 p个系数 计算 减小基音周期 提取共振峰 合成激励 合成语音 打开音频 男变女 开始 运行 女变男 变童声 洗手 洗手 洗手 1按
15、钮组 : b eef设计中使用了两个按钮组 , 吃饭 把 打开 、 beef原声 、 beef男变女 、 beef女变男 、 beef童声 三项功能放在一组 ; b eef另一个把语音的 图像 即 4个 axes放在了一组 。 洗手 洗手 2按钮 : beef最常用的控件 , 吃饭 用 于相应用户的鼠标单击 , 吃饭 按钮上有说明文字说明其作用 。 洗手 设计中使用了五 个按钮 , 吃饭 分别用于 打开 、 beef原声 、 beef男变女 、 beef女变男 、 beef童声 。 洗手 洗手 3 轴 : b eef 用于显示图像 。 洗手 洗手 3.2回调函数 洗手 对控件的 Callbac
16、k属性编程是实现 GUI的基本机制 , 吃饭 我们下来就要在各函数中编写程序代码 ,吃饭 完成各回调函数的功能 。 洗手 洗手 ( 1)打开 洗手 function dakai_Callback(hObject, eventdata, handles)洗手 filename,pathname=uigetfile(*.wav,ALL FILES,选择声音 );b e ef洗手 ifisequal(filename pathname,0,0)洗手 return;b eef洗手 end洗手 str=pathname filename;b e ef洗手 temp,Fs=audioread(str);b
17、eef洗手 temp1=resample(temp,80,441);beef洗手 handles.y=temp1;b e ef洗手 handles.y1=temp;b e ef洗手 handles.Fs=Fs;b e ef洗手 guidata(hObject,handles);beef洗手 ( 2)原声 洗手 function yuansheng_Callback(hObject, eventdata, handles)洗手 c=handles.Fs;b e ef洗手 sound(handles.y1,c);beef洗手 plot(handles.axes1,handles.y1)洗手 tit
18、le(handles.axes1,时域图 );beef洗手 图 4 界面设计 ysize=size(handles.y1);beef洗手 y1=fft(handles.y,length(handles.y1);beef洗手 ysize=size(y1);b e ef洗手 plot(handles.axes2,abs(y1);beef洗手 xlabel(handles.axes2,频率 );beef洗手 ylabel(handles.axes2,幅度 );beef洗手 title(handles.axes2,频率特性 );beef洗手 ( 3) 男变女 洗手 function nanbiannv
19、_Callback(hObject, eventdata, handles)洗手 FL = 80 ;b eef % 帧移 洗手 WL = 240 ;b eef % 窗长 洗手 P = 10 ;b eef %预测系数个数 洗手 s = handles.y;b e ef洗手 fs = handles.Fs;b e ef洗手 洗手 % 定义常数 洗手 s = s/max(s);b e ef % 归一化 洗手 L = length(s);b e ef % 读入语音长度 洗手 FN = floor(L/FL)-2;b e ef % 计算帧长 , 吃饭 floor; bef向负无穷方向 洗手 % 预测和重
20、建滤波器 洗手 exc = zeros(L,1);b e ef % 激励信号 , 吃饭 double类零矩阵 L行 1列 洗手 zi_pre = zeros(P,1);b e ef % 预测滤波器状态 洗手 s_rec = zeros(L,1);b e ef % 重建语音 洗手 zi_rec = zeros(P,1);b e ef洗手 % 变调滤波器 洗手 exc_syn_t = zeros(L,1);b e ef % 合成的激励信号 , 吃饭 创建一个 L行 1列的 0脉冲 洗手 s_syn_t = zeros(L,1);b e ef % 合成语音 洗手 last_syn_t = 0;b e
21、ef % 存储上一个段的最后一个脉冲的下标 洗手 zi_syn_t = zeros(P,1);b e ef % 合成滤波器 洗手 hw = hamming(WL);b e ef %汉明窗 洗手 %滤波器 洗手 洗手 % 依次处理每帧语音 洗手 for n = 3:FN %从第三个子数组开始 洗手 % 计算预测系数 洗手 s_w = s(n*FL-WL+1:n*FL).*hw;beef %汉明窗加权 洗手 A,E=lpc(s_w,P);beef %线性预测计算预测系数 洗手 % A是预测系数 , 吃饭 E会被用来计算合成激励的能量 洗手 s_f=s(n-1)*FL+1:n*FL);beef %
22、本帧语音 洗手 %利用 filter函数重建语音 洗手 洗手 exc1,zi_pre = filter(A,1,s_f,zi_pre);beef 洗手 exc(n-1)*FL+1:n*FL) = exc1;b eef %计算激励 洗手 %利用 filter函数重建语音 洗手 s_rec1,zi_rec = filter(1,A,exc1,zi_rec);beef洗手 s_rec(n-1)*FL+1:n*FL) = s_rec1;b e ef %重建语音 洗手 % 下面只有得到 exc后才可以 洗手 s_Pitch = exc(n*FL-222:n*FL);beef洗手 PT(n) = find
23、pitch(s_Pitch);beef %计算基音周期 pt洗手 G = sqrt(E*PT(n);b e ef %计算合成激励的能量 G洗手 % tempn_syn = 1:n*FL-last_syn;b e ef洗手 % exc_syn1 = zeros(length(tempn_syn),1);beef洗手 % exc_syn1(mod(tempn_syn,PT)=0) = G;b eef %某一段算出的脉冲 洗手 % exc_syn1 = exc_syn1(n-1)*FL-last_syn+1:n*FL-last_syn);beef洗手 % s_syn1,zi_syn = filter
24、(1,A,exc_syn1,zi_syn);beef洗手 % exc_syn(n-1)*FL+1:n*FL)=exc_syn1;beef %计算得到合成激励 洗手 % s_syn(n-1)*FL+1:n*FL) = s_syn1;b e ef %计算得到合成语音 洗手 % last_syn = last_syn+PT*floor(n*FL-last_syn)/PT);beef洗手 PT1 =floor(PT(n)/2);b e ef %减小基音周期 洗手 poles = roots(A);b e ef洗手 deltaOMG =100*2*pi/fs;b e ef洗手 洗手 for p=1:10
25、 %增加共振峰 洗手 ifimag(poles(p)0洗手 poles(p) = poles(p)*exp(1j*deltaOMG);beef洗手 elseifimag(poles(p)=0.85*Rop洗手 Rop=R2;b eef洗手 Top=T2;b eef洗手 end洗手 if R30.85*Rop洗手 Rop=R3;b eef洗手 Top=T3;b eef洗手 end洗手 PT=Top;b eef洗手 return洗手 ( 3)女变男 洗手 function nvbiannan_Callback(hObject, eventdata, handles)洗手 FL = 80 ;b ee
26、f % 帧移 洗手 WL = 240 ;b eef % 窗长 洗手 P = 10 ;b eef %预测系数个数 洗手 s = handles.y;b e ef洗手 fs = handles.Fs;b e ef洗手 洗手 % 定义常数 洗手 s = s/max(s);b e ef % 归一化 洗手 L = length(s);b e ef % 读入语音长度 洗手 FN = floor(L/FL)-2;b e ef % 计算帧长 , 吃饭 floor; bef向负无穷方向 洗手 % 预测和重建滤波器 洗手 exc = zeros(L,1);b e ef % 激励信号 , 吃饭 double类零矩阵
27、 L行 1列 洗手 zi_pre = zeros(P,1);b e ef % 预测滤波器状态 洗手 s_rec = zeros(L,1);b e ef % 重建语音 洗手 zi_rec = zeros(P,1);b e ef洗手 % 变调滤波器 洗手 exc_syn_t = zeros(L,1);b e ef % 合成的激励信号 , 吃饭 创建一个 L行 1列的 0脉冲 洗手 s_syn_t = zeros(L,1);b e ef % 合成语音 洗手 last_syn_t = 0;b eef % 存储上一个段的最后一个脉冲的下标 洗手 zi_syn_t = zeros(P,1);b e ef
28、% 合成滤波器 洗手 hw = hamming(WL);b e ef %汉明窗 洗手 %滤波器 洗手 洗手 % 依次处理每帧语音 洗手 for n = 3:FN %从第三个子数组开始 洗手 % 计算预测系数 洗手 s_w = s(n*FL-WL+1:n*FL).*hw;beef %汉明窗加权 洗手 A,E=lpc(s_w,P);beef %线性预测计算预测系数 洗手 % A是预测系数 , 吃饭 E会被用来计算合成激励的能量 洗手 s_f=s(n-1)*FL+1:n*FL);beef % 本帧语音 洗手 %利用 filter函数重建语音 洗手 洗手 exc1,zi_pre = filter(A,
29、1,s_f,zi_pre);beef 洗手 exc(n-1)*FL+1:n*FL) = exc1;b eef %计算激励 洗手 %利用 filter函数重建语音 洗手 s_rec1,zi_rec = filter(1,A,exc1,zi_rec);beef洗手 s_rec(n-1)*FL+1:n*FL) = s_rec1;b e ef %重建语音 洗手 % 下面只有得到 exc后才可以 洗手 s_Pitch = exc(n*FL-222:n*FL);beef洗手 PT(n) = findpitch(s_Pitch);beef %计算基音周期 pt洗手 G = sqrt(E*PT(n);b e
30、ef %计算合成激励的能量 G洗手 % tempn_syn = 1:n*FL-last_syn;b e ef洗手 % exc_syn1 = zeros(length(tempn_syn),1);beef洗手 % exc_syn1(mod(tempn_syn,PT)=0) = G;b eef %某一段算出的脉冲 洗手 % exc_syn1 = exc_syn1(n-1)*FL-last_syn+1:n*FL-last_syn);beef洗手 % s_syn1,zi_syn = filter(1,A,exc_syn1,zi_syn);beef洗手 % exc_syn(n-1)*FL+1:n*FL)
31、=exc_syn1;beef %计算得到合成激励 洗手 % s_syn(n-1)*FL+1:n*FL) = s_syn1;b e ef %计算得到合成语音 洗手 % last_syn = last_syn+PT*floor(n*FL-last_syn)/PT);beef洗手 PT1 =floor(PT(n)/2);b e ef %减小基音周期 洗手 poles = roots(A);b e ef洗手 deltaOMG =100*2*pi/fs;b e ef洗手 洗手 for p=1:10 %增加共振峰 洗手 ifimag(poles(p)0洗手 poles(p) = poles(p)*exp(
32、1j*deltaOMG);beef洗手 elseifimag(poles(p)0 洗手 poles(p) = poles(p)*exp(-1j*deltaOMG);beef洗手 end洗手 end洗手 end洗手 洗手 A1=poly(poles);b e ef洗手 洗手 tempn_syn_t=(1:n*FL-last_syn_t);beef洗手 exc_syn1_t = zeros(length(tempn_syn_t),1);beef洗手 exc_syn1_t(mod(tempn_syn_t,PT1)=0) = G;b eef 洗手 洗手 exc_syn1_t = exc_syn1_t(
33、n-1)*FL-last_syn_t+1:n*FL-last_syn_t);beef洗手 s_syn1_t,zi_syn_t = filter(1,A1,exc_syn1_t,zi_syn_t);beef洗手 exc_syn_t(n-1)*FL+1:n*FL) = exc_syn1_t;b e ef %合成激励 洗手 s_syn_t(n-1)*FL+1:n*FL) = s_syn1_t;b eef %合成语音 洗手 last_syn_t = last_syn_t+PT1*floor(n*FL-last_syn_t)/PT1);beef洗手 end洗手 %绘图 洗手 洗手 handles.y=s_syn_t;beef洗手 guidata(hObject,handles);beef洗手 %绘图 洗手 plot(handles.axes4,exc_syn_t)洗手 xlabel(handles.axes4,时域图 );beef洗手 ylabel(handles.axes4,频率 );beef洗手 title(handles.axes4,幅度 );beef洗手 handles.y=s_syn_t;beef洗手 guidata(hObject,handles);beef洗手 洗手 plot(handles.axes3,s_syn_t);beef洗手