diff 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 diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Code/Descriptors/Matlab/MPEG7/FromWeb/VoiceSauce/func_GetHNR.m	Wed Feb 13 11:02:39 2013 +0000
@@ -0,0 +1,127 @@
+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
+
+
+
+