承接(二)打算以后有时间补充原理
端点检测
function frameout=enframe(x,win,inc)
nx=length(x(:)); % 取数据长度
nwin=length(win); % 取窗长
if (nwin == 1) % 判断窗长是否为1,若为1,即表示没有设窗函数
len = win; % 是,帧长=win
else
len = nwin; % 否,帧长=窗长
end
if (nargin < 3) % 如果只有两个参数,设帧inc=帧长
inc = len;
end
nf = fix((nx-len+inc)/inc); % 计算帧数
frameout=zeros(nf,len); % 初始化
indf= inc*(0:(nf-1)).'; % 设置每帧在x中的位移量位置
inds = (1:len); % 每帧数据对应1:len
frameout(:) = x(indf(:,ones(1,len))+inds(ones(nf,1),:)); % 对数据分帧
if (nwin > 1) % 若参数中包括窗函数,把每帧乘以窗函数
w = win(:)'; % 把win转成行数据
frameout = frameout .* w(ones(nf,1),:); % 乘窗函数
end
function [x1,x2,FrameInc,amp,zcr] = vad(x)
%幅度归一化到[-1,1]
x = double(x);
x = x / max(abs(x));
%常数设置
FrameLen = 240;
FrameInc = 80;
amp1 = 10;
amp2 = 2;
zcr1 = 10;
zcr2 = 5;
maxsilence = 8; % 3*10ms = 30ms
minlen = 15; % 15*10ms = 150ms
status = 0;
count = 0;
silence = 0;
%计算过零率
tmp1 = enframe(x(1:end-1), FrameLen, FrameInc);
tmp2 = enframe(x(2:end) , FrameLen, FrameInc);
signs = (tmp1.*tmp2)<0;
diffs = (tmp1 -tmp2)>0.02;
zcr = sum(signs.*diffs, 2);
%计算短时能量
amp = sum(abs(enframe(filter([1 -0.9375], 1, x), FrameLen, FrameInc)), 2);
%调整能量门限
amp1 = min(amp1, max(amp)/4);
amp2 = min(amp2, max(amp)/8);
%开始端点检测
x1 = 0;
x2 = 0;
for n=1:length(zcr)
goto = 0;
switch status
case {0,1} % 0 = 静音, 1 = 可能开始
if amp(n) > amp1 % 确信进入语音段
x1 = max(n-count-1,1);
status = 2;
silence = 0;
count = count + 1;
elseif amp(n) > amp2 | ... % 可能处于语音段
zcr(n) > zcr2
status = 1;
count = count + 1;
else % 静音状态
status = 0;
count = 0;
end
case 2, % 2 = 语音段
if amp(n) > amp2 | ... % 保持在语音段
zcr(n) > zcr2
count = count + 1;
else % 语音将结束
silence = silence+1;
if silence < maxsilence % 静音还不够长,尚未结束
count = count + 1;
elseif count < minlen % 语音长度太短,认为是噪声
status = 0;
silence = 0;
count = 0;
else % 语音结束
status = 3;
end
end
case 3,
break;
end
end
count = count-silence/2;
x2 = x1 + count -1;
function soundSegment=findSegment(express)
if express(1)==0
voicedIndex=find(express); % 寻找express中为1的位置
else
voicedIndex=express;
end
soundSegment = [];
k = 1;
soundSegment(k).begin = voicedIndex(1); % 设置第一组有话段的起始位置
for i=1:length(voicedIndex)-1,
if voicedIndex(i+1)-voicedIndex(i)>1, % 本组有话段结束
soundSegment(k).end = voicedIndex(i); % 设置本组有话段的结束位置
soundSegment(k+1).begin = voicedIndex(i+1);% 设置下一组有话段的起始位置
k = k+1;
end
end
soundSegment(k).end = voicedIndex(end); % 最后一组有话段的结束位置
% 计算每组有话段的长度
for i=1 :k
soundSegment(i).duration=soundSegment(i).end-soundSegment(i).begin+1;
end
function frameTime=FrameTimeC(frameNum,framelen,inc,fs)
% 分帧后计算每帧对应的时间
frameTime=(((1:frameNum)-1)*inc+framelen/2)/fs;
function y=multimidfilter(x,m)
a=x;
for k=1 : m
b=medfilt1(a, 5);
a=b;
end
y=b;
%双门限法端点检测
[s1,fs]=audioread('R.wav'); %都是单声道哦,怎么录单声道博客里说过了
% 读入数据文件
subplot 311
[x1,x2,FrameInc,amp,zcr] = vad(s1);
plot(s1)
title('原信号','fontsize',10);
ylabel('幅度','fontsize',10);
xlabel('样点数','fontsize',10);
axis([1 length(s1) -0.2 0.2])
line([x1*FrameInc x1*FrameInc],[-0.1 0.1] , 'Color', 'red');
line([x2*FrameInc x2*FrameInc],[-0.1 0.1] ,'Color', 'red');
subplot 312
plot(amp);
title('短时能量','fontsize',10);
ylabel('能量值','fontsize',10);
xlabel('帧数','fontsize',10);
axis([1 length(amp) 0 max(amp)])
line([x1 x1], [min(amp),max(amp)], 'Color', 'red');
line([x2 x2], [min(amp),max(amp)], 'Color', 'red');
subplot 313
plot(zcr);
title('过零率','fontsize',10);
ylabel('过零次数','fontsize',10);
xlabel('帧数','fontsize',10);
axis([1 length(zcr) 0 max(zcr)])
line([x1 x1], [min(zcr),max(zcr)], 'Color', 'red');
line([x2 x2], [min(zcr),max(zcr)], 'Color', 'red');