view Code/Descriptors/Matlab/MPEG7/FromWeb/VoiceSauce/func_GetHNR.m @ 4:92ca03a8fa99 tip

Update to ICASSP 2013 benchmark
author Dawn Black
date Wed, 13 Feb 2013 11:02:39 +0000
parents
children
line wrap: on
line source
function [HNR05, HNR15, HNR25, HNR35] = func_GetHNR(y, Fs, F0, variables)
% N = func_GetHNR(y, Fs, F0, variables, textgridfile
% Input:  y, Fs - from wavread
%         F0 - vector of fundamental frequencies
%         variables - global settings
%         textgridfile - this is optional
% Output: N vectors
% Notes:  Calculates the Harmonic to noise ratio based on the method
% described in de Krom, 1993 - A cepstrum-based technique for determining a
% harmonic-to-noise ratio in speech signals, JSHR.
%
% Author: Yen-Liang Shue, Speech Processing and Auditory Perception Laboratory, UCLA
% Copyright UCLA SPAPL 2009

N_periods = variables.Nperiods_EC;
sampleshift = (Fs / 1000 * variables.frameshift);

HNR05 = zeros(length(F0), 1) * NaN;
HNR15 = zeros(length(F0), 1) * NaN;
HNR25 = zeros(length(F0), 1) * NaN;
HNR35 = zeros(length(F0), 1) * NaN;


for k=1:length(F0)
    ks = round(k * sampleshift);

    if (ks <= 0 || ks > length(y))
        continue;
    end

    F0_curr = F0(k);
    N0_curr = 1 / F0_curr * Fs;

    if (isnan(F0_curr))
        continue;
    end

    ystart = round(ks - N_periods/2*N0_curr);
    yend = round(ks + N_periods/2*N0_curr) - 1;

    if (mod(yend - ystart + 1, 2) == 0)  % length is even, make it odd
        yend = yend - 1;
    end

    if (ystart <= 0)
        continue;
    end;

    if (yend > length(y))
        continue;
    end;

    yseg = y(ystart:yend);


    hnr = getHNR(yseg, F0_curr, Fs, [500 1500 2500 3500]);

    HNR05(k) = hnr(1);
    HNR15(k) = hnr(2);
    HNR25(k) = hnr(3);
    HNR35(k) = hnr(4);

end


% main processing function
function n = getHNR(y, F0, Fs, Nfreqs)

NBins = length(y);
N0 = round(Fs / F0);
N0_delta = round(N0 * 0.1);  % search 10% either side

y = y .* hamming(length(y));
Y = fft(y, NBins);
aY = log10(abs(Y));
ay = ifft(aY);

% find possible rahmonic peaks
peakinx = zeros(floor(length(y)/ 2 / N0), 1);
for k=1:length(peakinx)
    ayseg = ay(k*N0 - N0_delta : k*N0 + N0_delta);
    [val, inx] = max(abs(ayseg));
    peakinx(k) = inx + k*N0 - N0_delta - 1;

    % lifter out each rahmonic peak
    s_ayseg = sign(diff(ayseg));
    
    % find first derivative sign change
    l_inx = inx - find((s_ayseg(inx-1:-1:1) ~= sign(inx)), 1) + 1;
    r_inx = inx + find((s_ayseg(inx+1:end) == sign(inx)), 1);
    
    l_inx = l_inx + k*N0 - N0_delta - 1;
    r_inx = r_inx + k*N0 - N0_delta - 1;
    
    % lifter out the peak
    ay(l_inx:r_inx) = 0;
   
end

% put the signal back together
midL = round(length(y) / 2) + 1;
ay(midL : end) = ay(midL - 1: -1 : midL - 1 - (length(ay) - midL));

Nap = real(fft(ay));
N = Nap;
Ha = aY - Nap;  % approximated harmonic spectrum

% calculate baseline corrections
Hdelta = F0 / Fs * length(y);
for f=Hdelta+0.0001:Hdelta:round(length(y)/2)
    fstart = ceil(f - Hdelta);
    
    Bdf = abs(min(Ha(fstart:round(f))));
    N(fstart:round(f)) = N(fstart:round(f)) - Bdf;
end

% calculate the average HNR for Nfreqs
H = aY - N;  %note that N is valid only for 1:length(N)/2
n = zeros(length(Nfreqs), 1);
for k=1:length(Nfreqs)
    Ef = round(Nfreqs(k) / Fs * length(y));  % equivalent cut off frequency
    n(k) = 20*mean(H(1:Ef)) - 20*mean(N(1:Ef));
end