annotate toolboxes/MIRtoolbox1.3.2/MIRToolbox/@mirpitch/mirpitch.m @ 0:cc4b1211e677 tip

initial commit to HG from Changeset: 646 (e263d8a21543) added further path and more save "camirversion.m"
author Daniel Wolff
date Fri, 19 Aug 2016 13:07:06 +0200
parents
children
rev   line source
Daniel@0 1 function varargout = mirpitch(orig,varargin)
Daniel@0 2 % p = mirpitch(x) evaluates the pitch frequencies (in Hz).
Daniel@0 3 % Specification of the method(s) for pitch estimation (these methods can
Daniel@0 4 % be combined):
Daniel@0 5 % mirpitch(...,'Autocor') computes an autocorrelation function
Daniel@0 6 % (Default method)
Daniel@0 7 % mirpitch(...'Enhanced',a) computes enhanced autocorrelation
Daniel@0 8 % (see help mirautocor)
Daniel@0 9 % toggled on by default
Daniel@0 10 % mirpitch(...,'Compress',k) performs magnitude compression
Daniel@0 11 % (see help mirautocor)
Daniel@0 12 % mirpitch(...,fb) specifies a type of filterbank.
Daniel@0 13 % Possible values:
Daniel@0 14 % fb = 'NoFilterBank': no filterbank decomposition
Daniel@0 15 % fb = '2Channels' (default value)
Daniel@0 16 % fb = 'Gammatone'
Daniel@0 17 % mirpitch(...,'AutocorSpectrum') computes the autocorrelation of
Daniel@0 18 % the FFT spectrum
Daniel@0 19 % mirpitch(...,'Cepstrum') computes the cepstrum
Daniel@0 20 % Alternatively, an autocorrelation or a cepstrum can be directly
Daniel@0 21 % given as first argument of the mirpitch function.
Daniel@0 22 % Peak picking options:
Daniel@0 23 % mirpitch(...,'Total',m) selects the m best pitches.
Daniel@0 24 % Default value: m = Inf, no limit is set concerning the number
Daniel@0 25 % of pitches to be detected.
Daniel@0 26 % mirpitch(...,'Mono') corresponds to morpitch(...,'Total',1)
Daniel@0 27 % mirpitch(...,'Min',mi) indicates the lowest frequency taken into
Daniel@0 28 % consideration.
Daniel@0 29 % Default value: 75 Hz. (Praat)
Daniel@0 30 % mirpitch(...,'Max',ma) indicates the highest frequency taken into
Daniel@0 31 % consideration.
Daniel@0 32 % Default value: 2400 Hz. Because there seems to be some problems
Daniel@0 33 % with higher frequency, due probably to the absence of
Daniel@0 34 % pre-whitening in our implementation of Tolonen and Karjalainen
Daniel@0 35 % approach (used by default, cf. below).
Daniel@0 36 % mirpitch(...,'Contrast',thr) specifies a threshold value.
Daniel@0 37 % (see help peaks)
Daniel@0 38 % Default value: thr = .1
Daniel@0 39 % mirpitch(...,'Order',o) specifies the ordering for the peak picking.
Daniel@0 40 % Default value: o = 'Amplitude'.
Daniel@0 41 % Alternatively, the result of a mirpeaks computation can be directly
Daniel@0 42 % given as first argument of the mirpitch function.
Daniel@0 43 % Post-processing options:
Daniel@0 44 % mirpitch(...,'Sum','no') does not sum back the channels at the end
Daniel@0 45 % of the computation. The resulting pitch information remains
Daniel@0 46 % therefore decomposed into several channels.
Daniel@0 47 % mirpitch(...,'Median') performs a median filtering of the pitch
Daniel@0 48 % curve. When several pitches are extracted in each frame, the
Daniel@0 49 % pitch curve contains the best peak of each successive frame.
Daniel@0 50 % mirpitch(...,'Stable',th,n) remove pitch values when the difference
Daniel@0 51 % (or more precisely absolute logarithmic quotient) with the
Daniel@0 52 % n precedent frames exceeds the threshold th.
Daniel@0 53 % if th is not specified, the default value .1 is used
Daniel@0 54 % if n is not specified, the default value 3 is used
Daniel@0 55 % mirpitch(...'Reso',r) removes peaks whose distance to one or
Daniel@0 56 % several higher peaks is lower than a given threshold.
Daniel@0 57 % Possible value for the threshold r:
Daniel@0 58 % 'SemiTone': ratio between the two peak positions equal to
Daniel@0 59 % 2^(1/12)
Daniel@0 60 % mirpitch(...,'Frame',l,h) orders a frame decomposition of window
Daniel@0 61 % length l (in seconds) and hop factor h, expressed relatively to
Daniel@0 62 % the window length. For instance h = 1 indicates no overlap.
Daniel@0 63 % Default values: l = 46.4 ms and h = 10 ms (Tolonen and
Daniel@0 64 % Karjalainen, 2000)
Daniel@0 65 % Preset model:
Daniel@0 66 % mirpitch(...,'Tolonen') implements (part of) the model proposed in
Daniel@0 67 % (Tolonen & Karjalainen, 2000). It is equivalent to
Daniel@0 68 % mirpitch(...,'Enhanced',2:10,'Generalized',.67,'2Channels')
Daniel@0 69 % [p,a] = mirpitch(...) also displays the result of the method chosen for
Daniel@0 70 % pitch estimation, and shows in particular the peaks corresponding
Daniel@0 71 % to the pitch values.
Daniel@0 72 % p = mirpitch(f,a,<r>) creates a mirpitch object based on the frequencies
Daniel@0 73 % specified in f and the related amplitudes specified in a, using a
Daniel@0 74 % frame sampling rate of r Hz (set by default to 100 Hz).
Daniel@0 75 %
Daniel@0 76 % T. Tolonen, M. Karjalainen, "A Computationally Efficient Multipitch
Daniel@0 77 % Analysis Model", IEEE TRANSACTIONS ON SPEECH AND AUDIO PROCESSING,
Daniel@0 78 % VOL. 8, NO. 6, NOVEMBER 2000
Daniel@0 79
Daniel@0 80 ac.key = 'Autocor';
Daniel@0 81 ac.type = 'Boolean';
Daniel@0 82 ac.default = 0;
Daniel@0 83 option.ac = ac;
Daniel@0 84
Daniel@0 85 enh.key = 'Enhanced';
Daniel@0 86 enh.type = 'Integer';
Daniel@0 87 enh.default = 2:10;
Daniel@0 88 option.enh = enh;
Daniel@0 89
Daniel@0 90 filtertype.type = 'String';
Daniel@0 91 filtertype.choice = {'NoFilterBank','2Channels','Gammatone'};
Daniel@0 92 filtertype.default = '2Channels';
Daniel@0 93 option.filtertype = filtertype;
Daniel@0 94
Daniel@0 95 gener.key = {'Generalized','Compress'};
Daniel@0 96 gener.type = 'Integer';
Daniel@0 97 gener.default = .5;
Daniel@0 98 option.gener = gener;
Daniel@0 99
Daniel@0 100 as.key = 'AutocorSpectrum';
Daniel@0 101 as.type = 'Boolean';
Daniel@0 102 as.default = 0;
Daniel@0 103 option.as = as;
Daniel@0 104
Daniel@0 105 s.key = 'Spectrum';
Daniel@0 106 s.type = 'Boolean';
Daniel@0 107 s.default = 0;
Daniel@0 108 option.s = s;
Daniel@0 109
Daniel@0 110 ce.key = 'Cepstrum';
Daniel@0 111 ce.type = 'Boolean';
Daniel@0 112 ce.default = 0;
Daniel@0 113 option.ce = ce;
Daniel@0 114
Daniel@0 115 %% peak picking options
Daniel@0 116
Daniel@0 117 m.key = 'Total';
Daniel@0 118 m.type = 'Integer';
Daniel@0 119 m.default = Inf;
Daniel@0 120 option.m = m;
Daniel@0 121
Daniel@0 122 multi.key = 'Multi';
Daniel@0 123 multi.type = 'Boolean';
Daniel@0 124 multi.default = 0;
Daniel@0 125 option.multi = multi;
Daniel@0 126
Daniel@0 127 mono.key = 'Mono';
Daniel@0 128 mono.type = 'Boolean';
Daniel@0 129 mono.default = 0;
Daniel@0 130 option.mono = mono;
Daniel@0 131
Daniel@0 132 mi.key = 'Min';
Daniel@0 133 mi.type = 'Integer';
Daniel@0 134 mi.default = 75;
Daniel@0 135 option.mi = mi;
Daniel@0 136
Daniel@0 137 ma.key = 'Max';
Daniel@0 138 ma.type = 'Integer';
Daniel@0 139 ma.default = 2400;
Daniel@0 140 option.ma = ma;
Daniel@0 141
Daniel@0 142 thr.key = 'Contrast';
Daniel@0 143 thr.type = 'Integer';
Daniel@0 144 thr.default = .1;
Daniel@0 145 option.thr = thr;
Daniel@0 146
Daniel@0 147 order.key = 'Order';
Daniel@0 148 order.type = 'String';
Daniel@0 149 order.choice = {'Amplitude','Abscissa'};
Daniel@0 150 order.default = 'Amplitude';
Daniel@0 151 option.order = order;
Daniel@0 152
Daniel@0 153 reso.key = 'Reso';
Daniel@0 154 reso.type = 'String';
Daniel@0 155 reso.choice = {0,'SemiTone'};
Daniel@0 156 reso.default = 0;
Daniel@0 157 option.reso = reso;
Daniel@0 158
Daniel@0 159 track.key = 'Track'; % Not used yet
Daniel@0 160 track.type = 'Boolean';
Daniel@0 161 track.default = 0;
Daniel@0 162 option.track = track;
Daniel@0 163
Daniel@0 164 %% post-processing options
Daniel@0 165
Daniel@0 166 stable.key = 'Stable';
Daniel@0 167 stable.type = 'Integer';
Daniel@0 168 stable.number = 2;
Daniel@0 169 stable.default = [Inf 0];
Daniel@0 170 stable.keydefault = [.1 3];
Daniel@0 171 option.stable = stable;
Daniel@0 172
Daniel@0 173 median.key = 'Median';
Daniel@0 174 median.type = 'Integer';
Daniel@0 175 median.default = 0;
Daniel@0 176 median.keydefault = .1;
Daniel@0 177 option.median = median;
Daniel@0 178
Daniel@0 179 frame.key = 'Frame';
Daniel@0 180 frame.type = 'Integer';
Daniel@0 181 frame.number = 2;
Daniel@0 182 frame.default = [0 0];
Daniel@0 183 frame.keydefault = [NaN NaN];
Daniel@0 184 option.frame = frame;
Daniel@0 185
Daniel@0 186 sum.key = 'Sum';
Daniel@0 187 sum.type = 'Boolean';
Daniel@0 188 sum.default = 1;
Daniel@0 189 option.sum = sum;
Daniel@0 190
Daniel@0 191 %% preset model
Daniel@0 192
Daniel@0 193 tolo.key = 'Tolonen';
Daniel@0 194 tolo.type = 'Boolean';
Daniel@0 195 tolo.default = 0;
Daniel@0 196 option.tolo = tolo;
Daniel@0 197
Daniel@0 198 specif.option = option;
Daniel@0 199 specif.chunkframebefore = 1;
Daniel@0 200
Daniel@0 201 if isnumeric(orig)
Daniel@0 202 if nargin<3
Daniel@0 203 f = 100;
Daniel@0 204 else
Daniel@0 205 f = varargin{2};
Daniel@0 206 end
Daniel@0 207 fp = (0:size(orig,1)-1)/f;
Daniel@0 208 fp = [fp;fp+1/f];
Daniel@0 209 p.amplitude = {{varargin{1}'}};
Daniel@0 210 s = mirscalar([],'Data',{{orig'}},'Title','Pitch','Unit','Hz',...
Daniel@0 211 'FramePos',{{fp}},'Sampling',f,'Name',{inputname(1)});
Daniel@0 212 p = class(p,'mirpitch',s);
Daniel@0 213 varargout = {p};
Daniel@0 214 else
Daniel@0 215 varargout = mirfunction(@mirpitch,orig,varargin,nargout,specif,@init,@main);
Daniel@0 216 end
Daniel@0 217
Daniel@0 218
Daniel@0 219
Daniel@0 220 function [y type] = init(orig,option)
Daniel@0 221 if option.tolo
Daniel@0 222 option.enh = 2:10;
Daniel@0 223 option.gener = .67;
Daniel@0 224 option.filtertype = '2Channels';
Daniel@0 225 end
Daniel@0 226 if not(option.ac) && not(option.as) && not(option.ce) && not(option.s)
Daniel@0 227 option.ac = 1;
Daniel@0 228 end
Daniel@0 229 if isnan(option.frame.length.val)
Daniel@0 230 option.frame.length.val = .0464;
Daniel@0 231 end
Daniel@0 232 if isnan(option.frame.hop.val)
Daniel@0 233 option.frame.hop.val = .01;
Daniel@0 234 option.frame.hop.unit = 's';
Daniel@0 235 end
Daniel@0 236 if isamir(orig,'mirscalar') || haspeaks(orig)
Daniel@0 237 y = orig;
Daniel@0 238 else
Daniel@0 239 if isamir(orig,'mirautocor')
Daniel@0 240 y = mirautocor(orig,'Min',option.mi,'Hz','Max',option.ma,'Hz','Freq');
Daniel@0 241 elseif isamir(orig,'mircepstrum')
Daniel@0 242 y = orig;
Daniel@0 243 elseif isamir(orig,'mirspectrum')
Daniel@0 244 if not(option.as) && not(option.ce) && not(option.s)
Daniel@0 245 option.ce = 1;
Daniel@0 246 end
Daniel@0 247 if option.as
Daniel@0 248 y = mirautocor(orig,...
Daniel@0 249 'Min',option.mi,'Hz','Max',option.ma,'Hz');
Daniel@0 250 end
Daniel@0 251 if option.ce
Daniel@0 252 ce = mircepstrum(orig,'freq',...
Daniel@0 253 'Min',option.mi,'Hz','Max',option.ma,'Hz');
Daniel@0 254 if option.as
Daniel@0 255 y = y*ce;
Daniel@0 256 else
Daniel@0 257 y = ce;
Daniel@0 258 end
Daniel@0 259 end
Daniel@0 260 else
Daniel@0 261 if option.ac
Daniel@0 262 x = orig;
Daniel@0 263 if not(strcmpi(option.filtertype,'NoFilterBank'))
Daniel@0 264 x = mirfilterbank(x,option.filtertype);
Daniel@0 265 end
Daniel@0 266 x = mirframenow(x,option);
Daniel@0 267 y = mirautocor(x,'Generalized',option.gener,...
Daniel@0 268 'Min',option.mi,'Hz','Max',option.ma,'Hz');
Daniel@0 269 if option.sum
Daniel@0 270 y = mirsummary(y);
Daniel@0 271 end
Daniel@0 272 y = mirautocor(y,'Enhanced',option.enh,'Freq');
Daniel@0 273 end
Daniel@0 274 if option.as || option.ce || option.s
Daniel@0 275 x = mirframenow(orig,option);
Daniel@0 276 y = mirspectrum(x);
Daniel@0 277 if option.as
Daniel@0 278 as = mirautocor(y,...
Daniel@0 279 'Min',option.mi,'Hz','Max',option.ma,'Hz');
Daniel@0 280 if option.ac
Daniel@0 281 y = y*as;
Daniel@0 282 else
Daniel@0 283 y = as;
Daniel@0 284 end
Daniel@0 285 end
Daniel@0 286 if option.ce
Daniel@0 287 ce = mircepstrum(y,'freq',...
Daniel@0 288 'Min',option.mi,'Hz','Max',option.ma,'Hz');
Daniel@0 289 if option.ac || option.as
Daniel@0 290 y = y*ce;
Daniel@0 291 else
Daniel@0 292 y = ce;
Daniel@0 293 end
Daniel@0 294 end
Daniel@0 295 end
Daniel@0 296 end
Daniel@0 297 end
Daniel@0 298 type = {'mirpitch',mirtype(y)};
Daniel@0 299
Daniel@0 300
Daniel@0 301 function o = main(x,option,postoption)
Daniel@0 302 if option.multi && option.m == 1
Daniel@0 303 option.m = Inf;
Daniel@0 304 end
Daniel@0 305 if option.mono && option.m == Inf
Daniel@0 306 option.m = 1;
Daniel@0 307 end
Daniel@0 308 if iscell(x)
Daniel@0 309 x = x{1};
Daniel@0 310 end
Daniel@0 311 if not(isa(x,'mirpitch'))
Daniel@0 312 x = mirpeaks(x,'Total',option.m,'Track',option.track,...
Daniel@0 313 'Contrast',option.thr,'Threshold',.4,...
Daniel@0 314 'Reso',option.reso,'NoBegin','NoEnd',...
Daniel@0 315 'Order',option.order);
Daniel@0 316 end
Daniel@0 317 if isa(x,'mirscalar')
Daniel@0 318 pf = get(x,'Data');
Daniel@0 319 else
Daniel@0 320 pf = get(x,'PeakPrecisePos');
Daniel@0 321 pa = get(x,'PeakPreciseVal');
Daniel@0 322 end
Daniel@0 323 fp = get(x,'FramePos');
Daniel@0 324 if option.stable(1) < Inf
Daniel@0 325 for i = 1:length(pf)
Daniel@0 326 for j = 1:length(pf{i})
Daniel@0 327 for k = 1:size(pf{i}{j},3)
Daniel@0 328 for l = size(pf{i}{j},2):-1:option.stable(2)+1
Daniel@0 329 for m = length(pf{i}{j}{1,l,k}):-1:1
Daniel@0 330 found = 0;
Daniel@0 331 for h = 1:option.stable(2)
Daniel@0 332 for n = 1:length(pf{i}{j}{1,l-h,k})
Daniel@0 333 if abs(log10(pf{i}{j}{1,l,k}(m) ...
Daniel@0 334 /pf{i}{j}{1,l-h,k}(n))) ...
Daniel@0 335 < option.stable(1)
Daniel@0 336 found = 1;
Daniel@0 337 end
Daniel@0 338 end
Daniel@0 339 end
Daniel@0 340 if not(found)
Daniel@0 341 pf{i}{j}{1,l,k}(m) = [];
Daniel@0 342 end
Daniel@0 343 end
Daniel@0 344 pf{i}{j}{1,1,k} = zeros(1,0);
Daniel@0 345 end
Daniel@0 346 end
Daniel@0 347 end
Daniel@0 348 end
Daniel@0 349 end
Daniel@0 350 if option.median
Daniel@0 351 sr = get(x,'Sampling');
Daniel@0 352 for i = 1:length(pf)
Daniel@0 353 for j = 1:length(pf{i})
Daniel@0 354 if size(fp{i}{j},2) > 1
Daniel@0 355 npf = zeros(size(pf{i}{j}));
Daniel@0 356 for k = 1:size(pf{i}{j},3)
Daniel@0 357 for l = 1:size(pf{i}{j},2)
Daniel@0 358 if isempty(pf{i}{j}{1,l,k})
Daniel@0 359 npf(1,l,k) = NaN;
Daniel@0 360 else
Daniel@0 361 npf(1,l,k) = pf{i}{j}{1,l,k}(1);
Daniel@0 362 end
Daniel@0 363 end
Daniel@0 364 end
Daniel@0 365 pf{i}{j} = medfilt1(npf,...
Daniel@0 366 round(option.median/(fp{i}{j}(1,2)-fp{i}{j}(1,1))));
Daniel@0 367 end
Daniel@0 368 end
Daniel@0 369 end
Daniel@0 370 end
Daniel@0 371 if isa(x,'mirscalar')
Daniel@0 372 p.amplitude = 0;
Daniel@0 373 else
Daniel@0 374 p.amplitude = pa;
Daniel@0 375 end
Daniel@0 376 s = mirscalar(x,'Data',pf,'Title','Pitch','Unit','Hz');
Daniel@0 377 p = class(p,'mirpitch',s);
Daniel@0 378 o = {p,x};