comparison toolboxes/MIRtoolbox1.3.2/MIRToolbox/mirpulseclarity.m @ 0:e9a9cd732c1e tip

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