annotate toolboxes/MIRtoolbox1.3.2/MIRToolbox/mirtempo.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 = mirtempo(x,varargin)
Daniel@0 2 % t = mirtempo(x) evaluates the tempo in beats per minute (BPM).
Daniel@0 3 % Optional arguments:
Daniel@0 4 % mirtempo(...,'Total',m) selects not only the best tempo, but the m
Daniel@0 5 % best tempos.
Daniel@0 6 % mirtempo(...,'Frame',l,h) orders a frame decomposition of window
Daniel@0 7 % length l (in seconds) and hop factor h, expressed relatively to
Daniel@0 8 % the window length. For instance h = 1 indicates no overlap.
Daniel@0 9 % Default values: l = 3 seconds and h = .1
Daniel@0 10 % mirtempo(...,'Min',mi) indicates the lowest tempo taken into
Daniel@0 11 % consideration, expressed in bpm.
Daniel@0 12 % Default value: 40 bpm.
Daniel@0 13 % mirtempo(...,'Max',ma) indicates the highest tempo taken into
Daniel@0 14 % consideration, expressed in bpm.
Daniel@0 15 % Default value: 200 bpm.
Daniel@0 16 % mirtempo(...,s) selects the tempo estimation strategy:
Daniel@0 17 % s = 'Autocor': Approach based on the computation of the
Daniel@0 18 % autocorrelation. (Default strategy)
Daniel@0 19 % Option associated to the mirautocor function can be
Daniel@0 20 % passed here as well (see help mirautocor):
Daniel@0 21 % 'Enhanced' (toggled on by default here)
Daniel@0 22 % s = 'Spectrum': Approach based on the computation of the
Daniel@0 23 % spectrum .
Daniel@0 24 % Option associated to the mirspectrum function can be
Daniel@0 25 % passed here as well (see help mirspectrum):
Daniel@0 26 % 'ZeroPad' (set by default to 10000 samples)
Daniel@0 27 % 'Prod' (toggled off by default)
Daniel@0 28 % These two strategies can be combined: the autocorrelation
Daniel@0 29 % function is translated into the frequency domain in order
Daniel@0 30 % to be compared to the spectrum curve.
Daniel@0 31 % tempo(...,'Autocor','Spectrum') multiplies the two curves.
Daniel@0 32 % Alternatively, an autocorrelation function ac or a spectrum sp
Daniel@0 33 % can be directly passed to the function tempo:
Daniel@0 34 % mirtempo(ac) or mirtempo(sp)
Daniel@0 35 % The options related to the onset detection phase can be specified
Daniel@0 36 % here as well (see help mironsets):
Daniel@0 37 % onset detection strategies: 'Envelope', 'DiffEnvelope'
Daniel@0 38 % (corresponding to 'Envelope', 'Diff'), 'SpectralFlux,
Daniel@0 39 % 'Pitch', 'Log', 'Mu', 'Filterbank'
Daniel@0 40 % mironsets(...,'Sum',w) specifies when to sum the channels.
Daniel@0 41 % Possible values:
Daniel@0 42 % w = 'Before': sum before the autocorrelation or
Daniel@0 43 % spectrum computation.
Daniel@0 44 % w = 'After': autocorrelation or spectrum computed
Daniel@0 45 % for each band, and summed into a "summary".
Daniel@0 46 % mirenvelope options: 'HalfwaveCenter','Diff' (toggled on by
Daniel@0 47 % default here),'HalfwaveDiff','Center','Smooth',
Daniel@0 48 % 'Sampling'
Daniel@0 49 % mirflux options: 'Inc','Halfwave','Complex','Median'
Daniel@0 50 % mirtempo(...,'Resonance',r) specifies the resonance curve, which
Daniel@0 51 % emphasizes the periods that are more easily perceived.
Daniel@0 52 % Possible values: 'ToiviainenSnyder' (default), 0 (toggled off)
Daniel@0 53 % Optional arguments used for the peak picking (cf. help mirpeaks)
Daniel@0 54 % mirtempo(...,'Contrast',thr): a threshold value. A given local
Daniel@0 55 % maximum will be considered as a peak if its distance with the
Daniel@0 56 % previous and successive local minima (if any) is higher than
Daniel@0 57 % this threshold. This distance is expressed with respect to the
Daniel@0 58 % total amplitude of the autocorrelation function.
Daniel@0 59 % if no value for thr is given, the value thr=0.1 is chosen
Daniel@0 60 % by default.
Daniel@0 61 %
Daniel@0 62 % [t,p] = mirtempo(...) also displays the result of the signal analysis
Daniel@0 63 % leading to the tempo estimation, and shows in particular the
Daniel@0 64 % peaks corresponding to the tempo values.
Daniel@0 65
Daniel@0 66
Daniel@0 67 sum.key = 'Sum';
Daniel@0 68 sum.type = 'String';
Daniel@0 69 sum.choice = {'Before','After','Adjacent',0};
Daniel@0 70 sum.default = 'Before';
Daniel@0 71 option.sum = sum;
Daniel@0 72
Daniel@0 73 %% options related to mironsets:
Daniel@0 74
Daniel@0 75 frame.key = 'Frame';
Daniel@0 76 frame.type = 'Integer';
Daniel@0 77 frame.number = 2;
Daniel@0 78 frame.default = [0 0];
Daniel@0 79 frame.keydefault = [3 .1];
Daniel@0 80 option.frame = frame;
Daniel@0 81
Daniel@0 82 fea.type = 'String';
Daniel@0 83 fea.choice = {'Envelope','DiffEnvelope','SpectralFlux','Pitch'};
Daniel@0 84 fea.default = 'Envelope';
Daniel@0 85 option.fea = fea;
Daniel@0 86
Daniel@0 87 %% options related to 'Envelope':
Daniel@0 88
Daniel@0 89 envmeth.key = 'Method';
Daniel@0 90 envmeth.type = 'String';
Daniel@0 91 envmeth.choice = {'Filter','Spectro'};
Daniel@0 92 envmeth.default = 'Filter';
Daniel@0 93 option.envmeth = envmeth;
Daniel@0 94
Daniel@0 95 %% options related to 'Filter':
Daniel@0 96
Daniel@0 97 fb.key = 'Filterbank';
Daniel@0 98 fb.type = 'Integer';
Daniel@0 99 fb.default = 10;
Daniel@0 100 option.fb = fb;
Daniel@0 101
Daniel@0 102 fbtype.key = 'FilterbankType';
Daniel@0 103 fbtype.type = 'String';
Daniel@0 104 fbtype.choice = {'Gammatone','Scheirer','Klapuri'};
Daniel@0 105 fbtype.default = 'Gammatone';
Daniel@0 106 option.fbtype = fbtype;
Daniel@0 107
Daniel@0 108 ftype.key = 'FilterType';
Daniel@0 109 ftype.type = 'String';
Daniel@0 110 ftype.choice = {'IIR','HalfHann'};
Daniel@0 111 ftype.default = 'IIR';
Daniel@0 112 option.ftype = ftype;
Daniel@0 113
Daniel@0 114 %% options related to 'Spectro':
Daniel@0 115
Daniel@0 116 band.type = 'String';
Daniel@0 117 band.choice = {'Freq','Mel','Bark','Cents'};
Daniel@0 118 band.default = 'Freq';
Daniel@0 119 option.band = band;
Daniel@0 120
Daniel@0 121
Daniel@0 122 chwr.key = 'HalfwaveCenter';
Daniel@0 123 chwr.type = 'Boolean';
Daniel@0 124 chwr.default = 0;
Daniel@0 125 option.chwr = chwr;
Daniel@0 126
Daniel@0 127 diff.key = 'Diff';
Daniel@0 128 diff.type = 'Boolean';
Daniel@0 129 diff.default = 1; % Different default for mirtempo
Daniel@0 130 option.diff = diff;
Daniel@0 131
Daniel@0 132 diffhwr.key = 'HalfwaveDiff';
Daniel@0 133 diffhwr.type = 'Integer';
Daniel@0 134 diffhwr.default = 0;
Daniel@0 135 diffhwr.keydefault = 1;
Daniel@0 136 option.diffhwr = diffhwr;
Daniel@0 137
Daniel@0 138 lambda.key = 'Lambda';
Daniel@0 139 lambda.type = 'Integer';
Daniel@0 140 lambda.default = 1;
Daniel@0 141 option.lambda = lambda;
Daniel@0 142
Daniel@0 143 mu.key = 'Mu';
Daniel@0 144 mu.type = 'Boolean';
Daniel@0 145 mu.default = 0;
Daniel@0 146 option.mu = mu;
Daniel@0 147
Daniel@0 148 log.key = 'Log';
Daniel@0 149 log.type = 'Boolean';
Daniel@0 150 log.default = 0;
Daniel@0 151 option.log = log;
Daniel@0 152
Daniel@0 153 c.key = 'Center';
Daniel@0 154 c.type = 'Boolean';
Daniel@0 155 c.default = 0;
Daniel@0 156 option.c = c;
Daniel@0 157
Daniel@0 158 aver.key = 'Smooth';
Daniel@0 159 aver.type = 'Integer';
Daniel@0 160 aver.default = 0;
Daniel@0 161 aver.keydefault = 30;
Daniel@0 162 option.aver = aver;
Daniel@0 163
Daniel@0 164 sampling.key = 'Sampling';
Daniel@0 165 sampling.type = 'Integer';
Daniel@0 166 sampling.default = 0;
Daniel@0 167 option.sampling = sampling;
Daniel@0 168
Daniel@0 169 %% options related to 'SpectralFlux'
Daniel@0 170
Daniel@0 171 complex.key = 'Complex';
Daniel@0 172 complex.type = 'Boolean';
Daniel@0 173 complex.default = 0;
Daniel@0 174 option.complex = complex;
Daniel@0 175
Daniel@0 176 inc.key = 'Inc';
Daniel@0 177 inc.type = 'Boolean';
Daniel@0 178 inc.default = 1;
Daniel@0 179 option.inc = inc;
Daniel@0 180
Daniel@0 181 median.key = 'Median';
Daniel@0 182 median.type = 'Integer';
Daniel@0 183 median.number = 2;
Daniel@0 184 median.default = [.2 1.3];
Daniel@0 185 option.median = median;
Daniel@0 186
Daniel@0 187 hw.key = 'Halfwave';
Daniel@0 188 hw.type = 'Boolean';
Daniel@0 189 hw.default = 1;
Daniel@0 190 option.hw = hw;
Daniel@0 191
Daniel@0 192
Daniel@0 193 %% options related to mirautocor:
Daniel@0 194
Daniel@0 195 aut.key = 'Autocor';
Daniel@0 196 aut.type = 'Integer';
Daniel@0 197 aut.default = 0;
Daniel@0 198 aut.keydefault = 1;
Daniel@0 199 option.aut = aut;
Daniel@0 200
Daniel@0 201 nw.key = 'NormalWindow';
Daniel@0 202 nw.default = 0;
Daniel@0 203 option.nw = nw;
Daniel@0 204
Daniel@0 205 enh.key = 'Enhanced';
Daniel@0 206 enh.type = 'Integers';
Daniel@0 207 enh.default = 2:10;
Daniel@0 208 enh.keydefault = 2:10;
Daniel@0 209 option.enh = enh;
Daniel@0 210
Daniel@0 211 r.key = 'Resonance';
Daniel@0 212 r.type = 'String';
Daniel@0 213 r.choice = {'ToiviainenSnyder','vanNoorden',0,'off','no'};
Daniel@0 214 r.default = 'ToiviainenSnyder';
Daniel@0 215 option.r = r;
Daniel@0 216
Daniel@0 217
Daniel@0 218 %% options related to mirspectrum:
Daniel@0 219
Daniel@0 220 spe.key = 'Spectrum';
Daniel@0 221 spe.type = 'Integer';
Daniel@0 222 spe.default = 0;
Daniel@0 223 spe.keydefault = 1;
Daniel@0 224 option.spe = spe;
Daniel@0 225
Daniel@0 226 zp.key = 'ZeroPad';
Daniel@0 227 zp.type = 'Integer';
Daniel@0 228 zp.default = 10000;
Daniel@0 229 zp.keydefault = Inf;
Daniel@0 230 option.zp = zp;
Daniel@0 231
Daniel@0 232 prod.key = 'Prod';
Daniel@0 233 prod.type = 'Integers';
Daniel@0 234 prod.default = 0;
Daniel@0 235 prod.keydefault = 2:6;
Daniel@0 236 option.prod = prod;
Daniel@0 237
Daniel@0 238
Daniel@0 239 %% options related to the peak detection
Daniel@0 240
Daniel@0 241 m.key = 'Total';
Daniel@0 242 m.type = 'Integer';
Daniel@0 243 m.default = 1;
Daniel@0 244 option.m = m;
Daniel@0 245
Daniel@0 246 thr.key = 'Contrast';
Daniel@0 247 thr.type = 'Integer';
Daniel@0 248 thr.default = 0.1;
Daniel@0 249 option.thr = thr;
Daniel@0 250
Daniel@0 251 mi.key = 'Min';
Daniel@0 252 mi.type = 'Integer';
Daniel@0 253 mi.default = 40;
Daniel@0 254 option.mi = mi;
Daniel@0 255
Daniel@0 256 ma.key = 'Max';
Daniel@0 257 ma.type = 'Integer';
Daniel@0 258 ma.default = 200;
Daniel@0 259 option.ma = ma;
Daniel@0 260
Daniel@0 261 track.key = 'Track';
Daniel@0 262 track.type = 'Boolean';
Daniel@0 263 track.default = 0;
Daniel@0 264 option.track = track;
Daniel@0 265
Daniel@0 266 pref.key = 'Pref';
Daniel@0 267 pref.type = 'Integer';
Daniel@0 268 pref.number = 2;
Daniel@0 269 pref.default = [0 .2];
Daniel@0 270 option.pref = pref;
Daniel@0 271
Daniel@0 272 perio.key = 'Periodicity';
Daniel@0 273 perio.type = 'Boolean';
Daniel@0 274 perio.default = 0;
Daniel@0 275 option.perio = perio;
Daniel@0 276
Daniel@0 277 specif.option = option;
Daniel@0 278
Daniel@0 279 varargout = mirfunction(@mirtempo,x,varargin,nargout,specif,@init,@main);
Daniel@0 280
Daniel@0 281
Daniel@0 282 %% INIT
Daniel@0 283
Daniel@0 284 function [y type] = init(x,option)
Daniel@0 285 if iscell(x)
Daniel@0 286 x = x{1};
Daniel@0 287 end
Daniel@0 288 if option.perio
Daniel@0 289 option.m = 3;
Daniel@0 290 option.enh = 2:10;
Daniel@0 291 end
Daniel@0 292 if not(isamir(x,'mirautocor')) && not(isamir(x,'mirspectrum'))
Daniel@0 293 if isframed(x) && strcmpi(option.fea,'Envelope') && not(isamir(x,'mirscalar'))
Daniel@0 294 warning('WARNING IN MIRTEMPO: The input should not be already decomposed into frames.');
Daniel@0 295 disp(['Suggestion: Use the ''Frame'' option instead.'])
Daniel@0 296 end
Daniel@0 297 if strcmpi(option.sum,'Before')
Daniel@0 298 optionsum = 1;
Daniel@0 299 elseif strcmpi(option.sum,'Adjacent')
Daniel@0 300 optionsum = 5;
Daniel@0 301 else
Daniel@0 302 optionsum = 0;
Daniel@0 303 end
Daniel@0 304 if option.frame.length.val
Daniel@0 305 x = mironsets(x,option.fea,'Filterbank',option.fb,...
Daniel@0 306 'FilterbankType',option.fbtype,...
Daniel@0 307 'FilterType',option.ftype,...
Daniel@0 308 'Sum',optionsum,'Method',option.envmeth,...
Daniel@0 309 option.band,'Center',option.c,...
Daniel@0 310 'HalfwaveCenter',option.chwr,'Diff',option.diff,...
Daniel@0 311 'HalfwaveDiff',option.diffhwr,'Lambda',option.lambda,...
Daniel@0 312 'Smooth',option.aver,'Sampling',option.sampling,...
Daniel@0 313 'Complex',option.complex,'Inc',option.inc,...
Daniel@0 314 'Median',option.median(1),option.median(2),...
Daniel@0 315 'Halfwave',option.hw,'Detect',0,...
Daniel@0 316 'Mu',option.mu,'Log',option.log,...
Daniel@0 317 'Frame',option.frame.length.val,...
Daniel@0 318 option.frame.length.unit,...
Daniel@0 319 option.frame.hop.val,...
Daniel@0 320 option.frame.hop.unit);
Daniel@0 321 else
Daniel@0 322 x = mironsets(x,option.fea,'Filterbank',option.fb,...
Daniel@0 323 'FilterbankType',option.fbtype,...
Daniel@0 324 'FilterType',option.ftype,...
Daniel@0 325 'Sum',optionsum,'Method',option.envmeth,...
Daniel@0 326 option.band,'Center',option.c,...
Daniel@0 327 'HalfwaveCenter',option.chwr,'Diff',option.diff,...
Daniel@0 328 'HalfwaveDiff',option.diffhwr,'Lambda',option.lambda,...
Daniel@0 329 'Smooth',option.aver,'Sampling',option.sampling,...
Daniel@0 330 'Complex',option.complex,'Inc',option.inc,...
Daniel@0 331 'Median',option.median(1),option.median(2),...
Daniel@0 332 'Halfwave',option.hw,'Detect',0,...
Daniel@0 333 'Mu',option.mu,'Log',option.log);
Daniel@0 334 end
Daniel@0 335 end
Daniel@0 336 if option.aut == 0 && option.spe == 0
Daniel@0 337 option.aut = 1;
Daniel@0 338 end
Daniel@0 339 if isamir(x,'mirautocor') || (option.aut && not(option.spe))
Daniel@0 340 y = mirautocor(x,'Min',60/option.ma,'Max',60/option.mi,...
Daniel@0 341 'Enhanced',option.enh,...'NormalInput','coeff',...
Daniel@0 342 'Resonance',option.r,'NormalWindow',option.nw);
Daniel@0 343 elseif isamir(x,'mirspectrum') || (option.spe && not(option.aut))
Daniel@0 344 y = mirspectrum(x,'Min',option.mi/60,'Max',option.ma/60,...
Daniel@0 345 'Prod',option.prod,...'NormalInput',...
Daniel@0 346 'ZeroPad',option.zp,'Resonance',option.r);
Daniel@0 347 elseif option.spe && option.aut
Daniel@0 348 ac = mirautocor(x,'Min',60/option.ma,'Max',60/option.mi,...
Daniel@0 349 'Enhanced',option.enh,...'NormalInput','coeff',...
Daniel@0 350 'Resonance',option.r);
Daniel@0 351 sp = mirspectrum(x,'Min',option.mi/60,'Max',option.ma/60,...
Daniel@0 352 'Prod',option.prod,...'NormalInput',...
Daniel@0 353 'ZeroPad',option.zp,'Resonance',option.r);
Daniel@0 354 y = ac*sp;
Daniel@0 355 end
Daniel@0 356 if ischar(option.sum)
Daniel@0 357 y = mirsum(y);
Daniel@0 358 end
Daniel@0 359 y = mirpeaks(y,'Total',option.m,'Track',option.track,...
Daniel@0 360 'Pref',option.pref(1),option.pref(2),...
Daniel@0 361 'Contrast',option.thr,'NoBegin','NoEnd',...
Daniel@0 362 'Normalize','Local');
Daniel@0 363 type = {'mirscalar',mirtype(y)};
Daniel@0 364
Daniel@0 365
Daniel@0 366 %% MAIN
Daniel@0 367
Daniel@0 368 function o = main(p,option,postoption)
Daniel@0 369 if iscell(p)
Daniel@0 370 p = p{1};
Daniel@0 371 end
Daniel@0 372 pt = get(p,'TrackPrecisePos');
Daniel@0 373 track = 1;
Daniel@0 374 if isempty(pt) || isempty(pt{1})
Daniel@0 375 pt = get(p,'PeakPrecisePos');
Daniel@0 376 track = 0;
Daniel@0 377 end
Daniel@0 378 bpm = cell(1,length(pt));
Daniel@0 379 for j = 1:length(pt)
Daniel@0 380 bpm{j} = cell(1,length(pt{j}));
Daniel@0 381 for k = 1:length(pt{j})
Daniel@0 382 ptk = pt{j}{k};
Daniel@0 383 bpmk = cell(1,size(ptk,2));
Daniel@0 384 for h = 1:size(ptk,3)
Daniel@0 385 for l = 1:size(ptk,2)
Daniel@0 386 ptl = ptk{1,l,h};
Daniel@0 387 if isempty(ptl)
Daniel@0 388 bpmk{1,l,h} = NaN;
Daniel@0 389 else
Daniel@0 390 if isa(p,'mirautocor') && not(get(p,'FreqDomain'))
Daniel@0 391 bpmk{1,l,h} = 60./ptl;
Daniel@0 392 else
Daniel@0 393 bpmk{1,l,h} = ptl*60;
Daniel@0 394 end
Daniel@0 395 end
Daniel@0 396 end
Daniel@0 397 end
Daniel@0 398 if track
Daniel@0 399 bpmk = bpmk{1};
Daniel@0 400 end
Daniel@0 401 bpm{j}{k} = bpmk;
Daniel@0 402 end
Daniel@0 403 end
Daniel@0 404 t = mirscalar(p,'Data',bpm,'Title','Tempo','Unit','bpm');
Daniel@0 405 o = {t,p};