annotate toolboxes/MIRtoolbox1.3.2/MIRToolbox/mirpulseclarity.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 = mirpulseclarity(orig,varargin)
Daniel@0 2 % r = mirpulseclarity(x) estimates the rhythmic clarity, indicating the
Daniel@0 3 % strength of the beats estimated by the mirtempo function.
Daniel@0 4 % Optional arguments:
Daniel@0 5 % mirpulseclarity(...,s): specifies a strategy for pulse clarity
Daniel@0 6 % estimation.
Daniel@0 7 % Possible values: 'MaxAutocor' (default), 'MinAutocor',
Daniel@0 8 % 'KurtosisAutocor', MeanPeaksAutocor', 'EntropyAutocor',
Daniel@0 9 % 'InterfAutocor', 'TempoAutocor', 'ExtremEnvelop',
Daniel@0 10 % 'Attack', 'Articulation'
Daniel@0 11 % mirpulseclarity(...,'Frame',l,h): orders a frame decomposition of
Daniel@0 12 % the audio input of window length l (in seconds) and hop factor
Daniel@0 13 % h, expressed relatively to the window length.
Daniel@0 14 % Default values: l = 5 seconds and h = .1
Daniel@0 15 % Onset detection strategies: 'Envelope' (default), 'DiffEnvelope',
Daniel@0 16 % 'SpectralFlux', 'Pitch'.
Daniel@0 17 % Options related to the autocorrelation computation can be specified
Daniel@0 18 % as well: 'Min', 'Max', 'Resonance', 'Enhanced'
Daniel@0 19 % Options related to the tempo estimation can be specified here
Daniel@0 20 % as well: 'Sum', 'Total', 'Contrast'.
Daniel@0 21 % cf. User's Manual for more details.
Daniel@0 22 % [r,a] = mirpulseclarity(x) also returns the beat autocorrelation.
Daniel@0 23
Daniel@0 24 model.key = 'Model';
Daniel@0 25 model.type = 'Integer';
Daniel@0 26 model.default = 0;
Daniel@0 27 option.model = model;
Daniel@0 28
Daniel@0 29 stratg.type = 'String';
Daniel@0 30 stratg.choice = {'MaxAutocor','MinAutocor','MeanPeaksAutocor',...
Daniel@0 31 'KurtosisAutocor','EntropyAutocor',...
Daniel@0 32 'InterfAutocor','TempoAutocor','ExtremEnvelop',...
Daniel@0 33 'Attack','Articulation'}; ...,'AttackDiff'
Daniel@0 34 stratg.default = 'MaxAutocor';
Daniel@0 35 option.stratg = stratg;
Daniel@0 36
Daniel@0 37 frame.key = 'Frame';
Daniel@0 38 frame.type = 'Integer';
Daniel@0 39 frame.number = 2;
Daniel@0 40 frame.keydefault = [5 .1];
Daniel@0 41 frame.default = [0 0];
Daniel@0 42 option.frame = frame;
Daniel@0 43
Daniel@0 44 %% options related to mironsets:
Daniel@0 45
Daniel@0 46 fea.type = 'String';
Daniel@0 47 fea.choice = {'Envelope','DiffEnvelope','SpectralFlux','Pitch'};
Daniel@0 48 fea.default = 'Envelope';
Daniel@0 49 option.fea = fea;
Daniel@0 50
Daniel@0 51
Daniel@0 52 %% options related to 'Envelope':
Daniel@0 53
Daniel@0 54 envmeth.key = 'Method';
Daniel@0 55 envmeth.type = 'String';
Daniel@0 56 envmeth.choice = {'Filter','Spectro'};
Daniel@0 57 envmeth.default = 'Spectro';
Daniel@0 58 option.envmeth = envmeth;
Daniel@0 59
Daniel@0 60 %% options related to 'Filter':
Daniel@0 61
Daniel@0 62 ftype.key = 'FilterType';
Daniel@0 63 ftype.type = 'String';
Daniel@0 64 ftype.choice = {'IIR','HalfHann'};
Daniel@0 65 ftype.default = 'IIR';
Daniel@0 66 option.ftype = ftype;
Daniel@0 67
Daniel@0 68 fb.key = 'Filterbank';
Daniel@0 69 fb.type = 'Integer';
Daniel@0 70 fb.default = 20;
Daniel@0 71 option.fb = fb;
Daniel@0 72
Daniel@0 73 fbtype.key = 'FilterbankType';
Daniel@0 74 fbtype.type = 'String';
Daniel@0 75 fbtype.choice = {'Gammatone','Scheirer','Klapuri'};
Daniel@0 76 fbtype.default = 'Scheirer';
Daniel@0 77 option.fbtype = fbtype;
Daniel@0 78
Daniel@0 79 %% options related to 'Spectro':
Daniel@0 80
Daniel@0 81 band.type = 'String';
Daniel@0 82 band.choice = {'Freq','Mel','Bark','Cents'};
Daniel@0 83 band.default = 'Freq';
Daniel@0 84 option.band = band;
Daniel@0 85
Daniel@0 86
Daniel@0 87 diffhwr.key = 'HalfwaveDiff';
Daniel@0 88 diffhwr.type = 'Integer';
Daniel@0 89 diffhwr.default = 0;
Daniel@0 90 diffhwr.keydefault = 1;
Daniel@0 91 option.diffhwr = diffhwr;
Daniel@0 92
Daniel@0 93 lambda.key = 'Lambda';
Daniel@0 94 lambda.type = 'Integer';
Daniel@0 95 lambda.default = 1;
Daniel@0 96 option.lambda = lambda;
Daniel@0 97
Daniel@0 98 aver.key = 'Smooth';
Daniel@0 99 aver.type = 'Integer';
Daniel@0 100 aver.default = 0;
Daniel@0 101 aver.keydefault = 30;
Daniel@0 102 option.aver = aver;
Daniel@0 103
Daniel@0 104 oplog.key = 'Log';
Daniel@0 105 oplog.type = 'Boolean';
Daniel@0 106 oplog.default = 0;
Daniel@0 107 option.log = oplog;
Daniel@0 108
Daniel@0 109 mu.key = 'Mu';
Daniel@0 110 mu.type = 'Boolean';
Daniel@0 111 mu.default = 1;
Daniel@0 112 option.mu = mu;
Daniel@0 113
Daniel@0 114 %% options related to 'SpectralFlux'
Daniel@0 115
Daniel@0 116 inc.key = 'Inc';
Daniel@0 117 inc.type = 'Boolean';
Daniel@0 118 inc.default = 1;
Daniel@0 119 option.inc = inc;
Daniel@0 120
Daniel@0 121 median.key = 'Median';
Daniel@0 122 median.type = 'Integer';
Daniel@0 123 median.number = 2;
Daniel@0 124 median.default = [0 0]; % Not same default as in mirtempo
Daniel@0 125 option.median = median;
Daniel@0 126
Daniel@0 127 hw.key = 'Halfwave';
Daniel@0 128 hw.type = 'Boolean';
Daniel@0 129 hw.default = 0; %NaN; %0; % Not same default as in mirtempo
Daniel@0 130 option.hw = hw;
Daniel@0 131
Daniel@0 132
Daniel@0 133 %% options related to mirattackslope
Daniel@0 134 slope.type = 'String';
Daniel@0 135 slope.choice = {'Diff','Gauss'};
Daniel@0 136 slope.default = 'Diff';
Daniel@0 137 option.slope = slope;
Daniel@0 138
Daniel@0 139 %% options related to mirautocor:
Daniel@0 140
Daniel@0 141 enh.key = 'Enhanced';
Daniel@0 142 enh.type = 'Integers';
Daniel@0 143 enh.default = [];
Daniel@0 144 enh.keydefault = 2:10;
Daniel@0 145 option.enh = enh;
Daniel@0 146
Daniel@0 147 r.key = 'Resonance';
Daniel@0 148 r.type = 'String';
Daniel@0 149 r.choice = {'ToiviainenSnyder','vonNoorden',0,'off','no'};
Daniel@0 150 r.default = 'ToiviainenSnyder';
Daniel@0 151 option.r = r;
Daniel@0 152
Daniel@0 153 mi.key = 'Min';
Daniel@0 154 mi.type = 'Integer';
Daniel@0 155 mi.default = 40;
Daniel@0 156 option.mi = mi;
Daniel@0 157
Daniel@0 158 ma.key = 'Max';
Daniel@0 159 ma.type = 'Integer';
Daniel@0 160 ma.default = 200;
Daniel@0 161 option.ma = ma;
Daniel@0 162
Daniel@0 163 %% options related to mirtempo:
Daniel@0 164
Daniel@0 165 sum.key = 'Sum';
Daniel@0 166 sum.type = 'String';
Daniel@0 167 sum.choice = {'Before','After','Adjacent'};
Daniel@0 168 sum.default = 'Before';
Daniel@0 169 option.sum = sum;
Daniel@0 170
Daniel@0 171 m.key = 'Total';
Daniel@0 172 m.type = 'Integer';
Daniel@0 173 m.default = 1;
Daniel@0 174 option.m = m;
Daniel@0 175
Daniel@0 176 thr.key = 'Contrast';
Daniel@0 177 thr.type = 'Integer';
Daniel@0 178 thr.default = 0.01; % Not same default as in mirtempo
Daniel@0 179 option.thr = thr;
Daniel@0 180
Daniel@0 181 specif.option = option;
Daniel@0 182
Daniel@0 183 varargout = mirfunction(@mirpulseclarity,orig,varargin,nargout,specif,@init,@main);
Daniel@0 184
Daniel@0 185
Daniel@0 186
Daniel@0 187 %% Initialisation
Daniel@0 188
Daniel@0 189 function [x type] = init(x,option)
Daniel@0 190 %if isframed(x)
Daniel@0 191 % warning('WARNING IN MIRPULSECLARITY: The input should not be already decomposed into frames.');
Daniel@0 192 % disp(['Suggestion: Use the ''Frame'' option instead.'])
Daniel@0 193 %end
Daniel@0 194 if iscell(x)
Daniel@0 195 x = x{1};
Daniel@0 196 end
Daniel@0 197 if isamir(x,'mirautocor')
Daniel@0 198 type = {'mirscalar','mirautocor'};
Daniel@0 199 elseif length(option.model) > 1
Daniel@0 200 a = x;
Daniel@0 201 type = {'mirscalar'};
Daniel@0 202 for m = 1:length(option.model)
Daniel@0 203 if option.frame.length.val
Daniel@0 204 y = mirpulseclarity(a,'Model',option.model(m),...
Daniel@0 205 'Frame',option.frame.length.val,...
Daniel@0 206 option.frame.length.unit,...
Daniel@0 207 option.frame.hop.val,...
Daniel@0 208 option.frame.hop.unit);
Daniel@0 209 else
Daniel@0 210 y = mirpulseclarity(a,'Model',option.model(m));
Daniel@0 211 end
Daniel@0 212 if m == 1
Daniel@0 213 x = y;
Daniel@0 214 else
Daniel@0 215 x = x + y;
Daniel@0 216 end
Daniel@0 217 end
Daniel@0 218 else
Daniel@0 219 if option.model
Daniel@0 220 switch option.model
Daniel@0 221 case 1
Daniel@0 222 case 2
Daniel@0 223 option.envmeth = 'Filter';
Daniel@0 224 option.fbtype = 'Gammatone';
Daniel@0 225 option.mu = 0;
Daniel@0 226 option.r = 0;
Daniel@0 227 option.lambda = .8;
Daniel@0 228 option.sum = 'After';
Daniel@0 229 end
Daniel@0 230 end
Daniel@0 231 if length(option.stratg)>7 && strcmpi(option.stratg(end-6:end),'Autocor')
Daniel@0 232 if (strcmpi(option.stratg,'MaxAutocor') || ...
Daniel@0 233 strcmpi(option.stratg,'MinAutocor') || ...
Daniel@0 234 strcmpi(option.stratg,'EntropyAutocor'))
Daniel@0 235 option.m = 0;
Daniel@0 236 end
Daniel@0 237 if strcmpi(option.stratg,'MinAutocor')
Daniel@0 238 option.enh = 0;
Daniel@0 239 end
Daniel@0 240 if option.frame.length.val
Daniel@0 241 [t,x] = mirtempo(x,option.fea,'Method',option.envmeth,...
Daniel@0 242 option.band,...
Daniel@0 243 'Sum',option.sum,'Enhanced',option.enh,...
Daniel@0 244 'Resonance',option.r,'Smooth',option.aver,...
Daniel@0 245 'HalfwaveDiff',option.diffhwr,...
Daniel@0 246 'Lambda',option.lambda,...
Daniel@0 247 'Frame',option.frame.length.val,...
Daniel@0 248 option.frame.length.unit,...
Daniel@0 249 option.frame.hop.val,...
Daniel@0 250 option.frame.hop.unit,...
Daniel@0 251 'FilterbankType',option.fbtype,...
Daniel@0 252 'FilterType',option.ftype,...
Daniel@0 253 'Filterbank',option.fb,'Mu',option.mu,...
Daniel@0 254 'Log',option.log,...
Daniel@0 255 'Inc',option.inc,'Halfwave',option.hw,...
Daniel@0 256 'Median',option.median(1),option.median(2),...
Daniel@0 257 'Min',option.mi,'Max',option.ma,...
Daniel@0 258 'Total',option.m,'Contrast',option.thr);
Daniel@0 259 else
Daniel@0 260 [t,x] = mirtempo(x,option.fea,'Method',option.envmeth,...
Daniel@0 261 option.band,...
Daniel@0 262 'Sum',option.sum,'Enhanced',option.enh,...
Daniel@0 263 'Resonance',option.r,'Smooth',option.aver,...
Daniel@0 264 'HalfwaveDiff',option.diffhwr,...
Daniel@0 265 'Lambda',option.lambda,...
Daniel@0 266 'FilterbankType',option.fbtype,...
Daniel@0 267 'FilterType',option.ftype,...
Daniel@0 268 'Filterbank',option.fb,'Mu',option.mu,...
Daniel@0 269 'Log',option.log,...
Daniel@0 270 'Inc',option.inc,'Halfwave',option.hw,...
Daniel@0 271 'Median',option.median(1),option.median(2),...
Daniel@0 272 'Min',option.mi,'Max',option.ma,...
Daniel@0 273 'Total',option.m,'Contrast',option.thr);
Daniel@0 274 end
Daniel@0 275 type = {'mirscalar','mirautocor'};
Daniel@0 276 elseif strcmpi(option.stratg,'ExtremEnvelop')
Daniel@0 277 x = mironsets(x,'Filterbank',option.fb);
Daniel@0 278 type = {'mirscalar','mirenvelope'};
Daniel@0 279 elseif strcmpi(option.stratg,'Attack')
Daniel@0 280 x = mirattackslope(x,option.slope);
Daniel@0 281 type = {'mirscalar','mirenvelope'};
Daniel@0 282 % elseif strcmpi(option.stratg,'AttackDiff')
Daniel@0 283 % type = {'mirscalar','mirenvelope'};
Daniel@0 284 elseif strcmpi(option.stratg,'Articulation')
Daniel@0 285 x = mirlowenergy(x,'ASR');
Daniel@0 286 type = {'mirscalar','mirscalar'};
Daniel@0 287 else
Daniel@0 288 type = {'mirscalar','miraudio'};
Daniel@0 289 end
Daniel@0 290 end
Daniel@0 291
Daniel@0 292
Daniel@0 293
Daniel@0 294 %% Main function
Daniel@0 295
Daniel@0 296 function o = main(a,option,postoption)
Daniel@0 297 if option.model == 2
Daniel@0 298 option.stratg = 'InterfAutocor';
Daniel@0 299 end
Daniel@0 300 if isa(a,'mirscalar') && not(strcmpi(option.stratg,'Attack')) % not very nice test... to improve.
Daniel@0 301 o = {a};
Daniel@0 302 return
Daniel@0 303 end
Daniel@0 304 if option.m == 1 && ...
Daniel@0 305 (strcmpi(option.stratg,'InterfAutocor') || ...
Daniel@0 306 strcmpi(option.stratg,'MeanPeaksAutocor'))
Daniel@0 307 option.m = Inf;
Daniel@0 308 end
Daniel@0 309 if iscell(a)
Daniel@0 310 a = a{1};
Daniel@0 311 end
Daniel@0 312 if strcmpi(option.stratg,'MaxAutocor')
Daniel@0 313 d = get(a,'Data');
Daniel@0 314 rc = mircompute(@max,d);
Daniel@0 315 elseif strcmpi(option.stratg,'MinAutocor')
Daniel@0 316 d = get(a,'Data');
Daniel@0 317 rc = mircompute(@minusmin,d);
Daniel@0 318 elseif strcmpi(option.stratg,'MeanPeaksAutocor')
Daniel@0 319 m = get(a,'PeakVal');
Daniel@0 320 rc = mircompute(@meanpeaks,m);
Daniel@0 321 elseif strcmpi(option.stratg,'KurtosisAutocor')
Daniel@0 322 a = mirpeaks(a,'Extract','Total',option.m,'NoBegin','NoEnd');
Daniel@0 323 k = mirkurtosis(a);
Daniel@0 324 %d = get(k,'Data');
Daniel@0 325 %rc = mircompute(@meanpeaks,d);
Daniel@0 326 rc = mirmean(k);
Daniel@0 327 elseif strcmpi(option.stratg,'EntropyAutocor')
Daniel@0 328 rc = mirentropy(a);
Daniel@0 329 elseif strcmpi(option.stratg,'InterfAutocor')
Daniel@0 330 a = mirpeaks(a,'Total',option.m,'NoBegin','NoEnd');
Daniel@0 331 m = get(a,'PeakVal');
Daniel@0 332 p = get(a,'PeakPosUnit');
Daniel@0 333 rc = mircompute(@interf,m,p);
Daniel@0 334 elseif strcmpi(option.stratg,'TempoAutocor')
Daniel@0 335 a = mirpeaks(a,'Total',1,'NoBegin','NoEnd');
Daniel@0 336 p = get(a,'PeakPosUnit');
Daniel@0 337 rc = mircompute(@tempo,p);
Daniel@0 338 elseif strcmpi(option.stratg,'ExtremEnvelop')
Daniel@0 339 a = mirenvelope(a,'Normal');
Daniel@0 340 p = mirpeaks(a,'Order','Abscissa');
Daniel@0 341 p = get(p,'PeakPreciseVal');
Daniel@0 342 n = mirpeaks(a,'Valleys','Order','Abscissa');
Daniel@0 343 n = get(n,'PeakPreciseVal');
Daniel@0 344 rc = mircompute(@shape,p,n);
Daniel@0 345 elseif strcmpi(option.stratg,'Attack')
Daniel@0 346 rc = mirmean(a);
Daniel@0 347 %elseif strcmpi(option.stratg,'AttackDiff')
Daniel@0 348 % a = mirpeaks(a);
Daniel@0 349 % m = get(a,'PeakVal');
Daniel@0 350 % rc = mircompute(@meanpeaks,m);
Daniel@0 351 elseif strcmpi(option.stratg,'Articulation')
Daniel@0 352 rc = a;
Daniel@0 353 end
Daniel@0 354
Daniel@0 355 if iscell(rc)
Daniel@0 356 pc = mirscalar(a,'Data',rc,'Title','Pulse clarity');
Daniel@0 357 else
Daniel@0 358 pc = set(rc,'Title',['Pulse clarity (',get(rc,'Title'),')']);
Daniel@0 359 end
Daniel@0 360
Daniel@0 361 if option.model
Daniel@0 362 switch option.model
Daniel@0 363 case 1
Daniel@0 364 alpha = 0;
Daniel@0 365 beta = 2.2015;
Daniel@0 366 lambda = .1;
Daniel@0 367 case 2
Daniel@0 368 alpha = 0;
Daniel@0 369 beta = 3.5982;
Daniel@0 370 lambda = 1.87;
Daniel@0 371 end
Daniel@0 372 if not(lambda == 0)
Daniel@0 373 pc = (pc+alpha)^lambda * beta;
Daniel@0 374 else
Daniel@0 375 pc = log(pc+alpha) * beta;
Daniel@0 376 end
Daniel@0 377 title = ['Pulse clarity (Model ',num2str(option.model),')'];
Daniel@0 378 pc = set(pc,'Title',title);
Daniel@0 379 end
Daniel@0 380
Daniel@0 381 o = {pc a};
Daniel@0 382
Daniel@0 383
Daniel@0 384 %% Routines
Daniel@0 385
Daniel@0 386 function r = shape(p,n)
Daniel@0 387 p = p{1};
Daniel@0 388 n = n{1};
Daniel@0 389 if length(p)>length(n)
Daniel@0 390 d = sum(p(1:end-1) - n) + sum(p(2:end) - n);
Daniel@0 391 r = d/(2*length(n));
Daniel@0 392 elseif length(p)<length(n)
Daniel@0 393 d = sum(p - n(1:end-1)) + sum(p - n(2:end));
Daniel@0 394 r = d/(2*length(p));
Daniel@0 395 else
Daniel@0 396 d = sum(p(2:end) - n(1:end-1)) + sum(p(1:end-1) - n(2:end));
Daniel@0 397 r = d/(2*(length(p)-1));
Daniel@0 398 end
Daniel@0 399
Daniel@0 400
Daniel@0 401 function rc = minusmin(ac)
Daniel@0 402 rc = -min(ac);
Daniel@0 403
Daniel@0 404
Daniel@0 405 function rc = meanpeaks(ac)
Daniel@0 406 rc = zeros(1,length(ac));
Daniel@0 407 for j = 1:length(ac)
Daniel@0 408 if isempty(ac{j})
Daniel@0 409 rc(j) = NaN;
Daniel@0 410 else
Daniel@0 411 rc(j) = mean(ac{j});
Daniel@0 412 end
Daniel@0 413 end
Daniel@0 414
Daniel@0 415
Daniel@0 416 function rc = interf(mk,pk)
Daniel@0 417 rc = zeros(size(mk));
Daniel@0 418 for j = 1:size(mk,3)
Daniel@0 419 for i = 1:size(mk,2)
Daniel@0 420 pij = pk{1,i,j};
Daniel@0 421 mij = mk{1,i,j};
Daniel@0 422 if isempty(pij)
Daniel@0 423 rc(1,i,j) = 0;
Daniel@0 424 else
Daniel@0 425 high = max(pij(2:end),pij(1));
Daniel@0 426 low = min(pij(2:end),pij(1));
Daniel@0 427 quo = rem(high,low)./low;
Daniel@0 428 nomult = quo>.15 & quo<.85;
Daniel@0 429 fij = mij(2:end)/mij(1) .*nomult;
Daniel@0 430 fij(fij<0) = 0;
Daniel@0 431 rc(1,i,j) = exp(-sum(fij)/4); % Pulsations that are not in integer ratio
Daniel@0 432 % with dominant pulse decrease clarity
Daniel@0 433 end
Daniel@0 434 end
Daniel@0 435 end
Daniel@0 436
Daniel@0 437
Daniel@0 438 function rc = tempo(pk)
Daniel@0 439 rc = zeros(size(pk));
Daniel@0 440 for j = 1:size(pk,3)
Daniel@0 441 for i = 1:size(pk,2)
Daniel@0 442 pij = pk{1,i,j};
Daniel@0 443 if isempty(pij)
Daniel@0 444 rc(1,i,j) = 0;
Daniel@0 445 else
Daniel@0 446 rc(1,i,j) = exp(-pij(1)/4)/exp(-.33/4); % Fast dominant pulse
Daniel@0 447 % increases clarity
Daniel@0 448 end
Daniel@0 449 end
Daniel@0 450 end