www.pudn.com > audioProcessingtoolbox.rar > frame2pitch.m
function [pitch, frame2, frame3, amdf]=frame2pitch(frame, plotOpt, PP, mainWindow, correctPitch);
%frame2pitch: Frame to pitch conversion (模擬SPCE061A,所以盡量模擬整數運算)
% Usage: pitch=frame2pitch(frame, plotOpt, PP);
% frame: Each element is unsigned integer between 0 and 255 (inclusive).
% plotOpt: 1 for plotting, 0 for not plotting
% pitch: Output pitch in semitone
% Roger Jang, 20021201
if nargin<1, selfdemo; return; end
if nargin<2, plotOpt=0; end
if nargin<3, [PP, CP]=setParam; end
if nargin<4, mainWindow=0; end
if nargin<5, correctPitch=0; end
%saveAscii(frame, 'text/frame.txt')
PP.maxFreq=pitch2freq(PP.maxPitch);
PP.minFreq=pitch2freq(PP.minPitch);
fs=PP.fs;
maxShift=PP.maxShift;
frameSize=length(frame);
% 如果音量太小,則直接回傳 0
%if sum(abs(frame-128)) < 9*256,
% pitch = 0;
% return;
%end
% 求 frame 的平均值為
average=intDiv(sum(frame), frameSize);
frame=frame-average;
% frame2: 如果前半音框音量小於後半音框,進行鏡射
frame2=frameFlip(frame, plotOpt);
% frame3: 平滑化
frame3=localAverage(frame2); % Low-pass filter implemented as local average
% ====== 計算 AMDF 曲線
amdf=frame2smdf(frame3, maxShift, 3);
% ====== 找出 ROI
beginIndex=ceil(PP.fs/PP.maxFreq);
endIndex=min(floor(PP.fs/PP.minFreq), PP.maxShift);
% Move beginIndex forward until amdf is going down
for i=beginIndex:endIndex-1,
if amdf(i)>amdf(i+1),
break;
end
end
beginIndex=i+1;
if beginIndex==endIndex
% fprintf('beginIndex==endIndex ==> pitch = 0!\n');
pitch=0;
plotFrame(plotOpt, frame, frame3, amdf, [], [], beginIndex, endIndex, mainWindow, correctPitch, PP.maxShift);
return;
end
% ====== 找出 ROI 的 local minima
localMinIndex=[];
for i=beginIndex+1:endIndex-1
if amdf(i-1)>amdf(i) & amdf(i)<=amdf(i+1)
localMinIndex=[localMinIndex, i];
end
end
n=20;
if length(localMinIndex)>=n, % 應該是氣音(但對女聲會誤判)
pitch=0;
if plotOpt, fprintf('Local minima 超過 %d 個 ==> pitch = 0!\n', n); end
plotFrame(plotOpt, frame, frame3, amdf, localMinIndex, [], beginIndex, endIndex, mainWindow, correctPitch, PP.maxShift);
return
end
% ====== 找最小值 in ROI
roi=amdf(beginIndex:endIndex); % region of interest
[minValue, minIndex]=min(roi);
minIndex=minIndex+beginIndex-1;
% ===== 從 minIndex 往回找可能出現的 2, 3, 4, 5, 6 倍頻
[maxValue, maxIndex]=max(roi);
difthreshold=minValue+floor((maxValue-minValue)/8);
for i=1:length(localMinIndex)
if amdf(localMinIndex(i)) <= difthreshold
if abs(floor((minIndex-1+3)/6)-(localMinIndex(i)-1)) <= floor(6/6)
if plotOpt, fprintf('代換成 6 倍頻!\n'); end
minIndex=localMinIndex(i);
break;
elseif abs(floor((2*minIndex-1+5)/10)-(localMinIndex(i)-1)) <= floor(6/5)
if plotOpt, fprintf('代換成 5 倍頻!\n'); end
minIndex=localMinIndex(i);
break;
elseif abs(floor((minIndex-1+2)/4)-(localMinIndex(i)-1)) <= floor(6/4)
if plotOpt, fprintf('代換成 4 倍頻!\n'); end
minIndex=localMinIndex(i);
break;
elseif abs(floor((2*minIndex-1+3)/6)-(localMinIndex(i)-1)) <= floor(6/3)
if plotOpt, fprintf('代換成 3 倍頻!\n'); end
minIndex=localMinIndex(i);
break;
elseif abs(floor((minIndex-1+1)/2)-(localMinIndex(i)-1)) <= floor(6/2)
if plotOpt, fprintf('代換成 2 倍頻!\n'); end
minIndex=localMinIndex(i);
break;
end
end
end
%freq=floor((10*PP.fs+floor((minIndex-1)/2))/(minIndex-1)); % 取第一個 minimum 來計算基頻(會爆掉!)
freq=10*floor((PP.fs+floor((minIndex-1)/2))/(minIndex-1)); % 取第一個 minimum 來計算基頻
%fprintf('minIndex=%d\n', minIndex);
%fprintf('freq=%d\n', freq);
pitch=freq2pitch(freq);
% ====== Plot all related information
plotFrame(plotOpt, frame, frame3, amdf, localMinIndex, minIndex, beginIndex, endIndex, mainWindow, correctPitch, PP.maxShift);
% ====== Plot related information
function plotFrame(plotOpt, frame, frame3, amdf, localMinIndex, minIndex, beginIndex, endIndex, mainWindow, correctPitch, maxShift)
if plotOpt,
frameSize=length(frame);
subplot(2,1,1);
% plot(1:length(frame), frame, '.-', 1:length(frame3), frame3, '.-'); grid on
frameH=plot(1:length(frame), frame, '.-'); grid on
set(frameH, 'tag', 'frame');
title(['Frame (frameSize=', int2str(frameSize), ')']);
set(gca, 'xlim', [1 frameSize]);
subplot(2,1,2);
amdfH=plot(amdf, '.-'); grid on
set(amdfH, 'tag', 'amdf');
amdfAxisH=gca;
set(gca, 'tag', 'amdfAxis');
title(['amdf (maxShift=', int2str(maxShift), ')']);
set(gca, 'xlim', [1 maxShift]);
if ~isempty(localMinIndex)
localMinIndexH=line(localMinIndex, amdf(localMinIndex), 'linestyle', 'none', 'color', 'k', 'marker', 'o', 'tag', 'localMinIndexH');
end
if ~isempty(minIndex)
minIndexH=line(minIndex, amdf(minIndex), 'linestyle', 'none', 'color', 'r', 'marker', 'o', 'tag', 'minIndexH');
if correctPitch==0
minIndex=nan;
else
minIndex=round(1+8000/(440*2^((correctPitch/10-69)/12)));
end
manualBarH=line(minIndex*[1 1], get(amdfAxisH, 'ylim'), 'color', 'm', 'erase', 'xor', 'tag', 'manualBar');
end
line(beginIndex*[1 1], get(gca, 'ylim'), 'color', 'r');
line( endIndex*[1 1], get(gca, 'ylim'), 'color', 'r');
set(gcf, 'name', mfilename);
% 設定滑鼠按鈕的反應動作,以便讓使用者修正 pitch
if mainWindow>0;
set(gcf, 'userdata', mainWindow);
frameWinMouseAction;
end
end
% ====== selfdemo
function selfdemo
waveFile='兩隻老虎.wav';
[y, PP.fs, nbits]=wavread(waveFile);
y=y*(2^nbits/2);
frameSize=256;
overlap=-256;
framedY=buffer2(y, frameSize, overlap);
frame=framedY(:, 100);
plotOpt=1;
feval(mfilename, frame, plotOpt);