diff 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
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/toolboxes/MIRtoolbox1.3.2/MIRToolbox/mirpulseclarity.m	Tue Feb 10 15:05:51 2015 +0000
@@ -0,0 +1,450 @@
+function varargout = mirpulseclarity(orig,varargin)
+%   r = mirpulseclarity(x) estimates the rhythmic clarity, indicating the
+%       strength of the beats estimated by the mirtempo function.
+%   Optional arguments:
+%       mirpulseclarity(...,s): specifies a strategy for pulse clarity
+%           estimation.
+%           Possible values: 'MaxAutocor' (default), 'MinAutocor',
+%               'KurtosisAutocor', MeanPeaksAutocor', 'EntropyAutocor', 
+%               'InterfAutocor', 'TempoAutocor', 'ExtremEnvelop', 
+%               'Attack', 'Articulation'
+%       mirpulseclarity(...,'Frame',l,h): orders a frame decomposition of
+%           the audio input of window length l (in seconds) and hop factor
+%           h, expressed relatively to the window length.
+%           Default values: l = 5 seconds and h = .1
+%       Onset detection strategies: 'Envelope' (default), 'DiffEnvelope', 
+%           'SpectralFlux', 'Pitch'.
+%       Options related to the autocorrelation computation can be specified
+%           as well: 'Min', 'Max', 'Resonance', 'Enhanced'
+%       Options related to the tempo estimation can be specified here
+%           as well: 'Sum', 'Total', 'Contrast'.
+%       cf. User's Manual for more details.
+%   [r,a] = mirpulseclarity(x) also returns the beat autocorrelation.
+        
+        model.key = 'Model';
+        model.type = 'Integer';
+        model.default = 0;
+    option.model = model;
+
+        stratg.type = 'String';
+        stratg.choice = {'MaxAutocor','MinAutocor','MeanPeaksAutocor',...
+                         'KurtosisAutocor','EntropyAutocor',...
+                         'InterfAutocor','TempoAutocor','ExtremEnvelop',...
+                         'Attack','Articulation'};    ...,'AttackDiff'
+        stratg.default = 'MaxAutocor';
+    option.stratg = stratg;
+
+        frame.key = 'Frame';
+        frame.type = 'Integer';
+        frame.number = 2;
+        frame.keydefault = [5 .1];
+        frame.default = [0 0];
+    option.frame = frame;
+        
+%% options related to mironsets:  
+
+        fea.type = 'String';
+        fea.choice = {'Envelope','DiffEnvelope','SpectralFlux','Pitch'};
+        fea.default = 'Envelope';
+    option.fea = fea;
+    
+    
+    %% options related to 'Envelope':
+    
+            envmeth.key = 'Method';
+            envmeth.type = 'String';
+            envmeth.choice = {'Filter','Spectro'};
+            envmeth.default = 'Spectro';
+        option.envmeth = envmeth;
+
+            %% options related to 'Filter':
+
+                ftype.key = 'FilterType';
+                ftype.type = 'String';
+                ftype.choice = {'IIR','HalfHann'};
+                ftype.default = 'IIR';
+            option.ftype = ftype;
+
+                fb.key = 'Filterbank';
+                fb.type = 'Integer';
+                fb.default = 20;
+            option.fb = fb;
+
+                fbtype.key = 'FilterbankType';
+                fbtype.type = 'String';
+                fbtype.choice = {'Gammatone','Scheirer','Klapuri'};
+                fbtype.default = 'Scheirer';
+            option.fbtype = fbtype;
+
+            %% options related to 'Spectro':
+
+                band.type = 'String';
+                band.choice = {'Freq','Mel','Bark','Cents'};
+                band.default = 'Freq';
+            option.band = band;
+
+
+            diffhwr.key = 'HalfwaveDiff';
+            diffhwr.type = 'Integer';
+            diffhwr.default = 0;
+            diffhwr.keydefault = 1;
+        option.diffhwr = diffhwr;
+
+            lambda.key = 'Lambda';
+            lambda.type = 'Integer';
+            lambda.default = 1;
+        option.lambda = lambda;
+
+            aver.key = 'Smooth';
+            aver.type = 'Integer';
+            aver.default = 0;
+            aver.keydefault = 30;
+        option.aver = aver;
+
+            oplog.key = 'Log';
+            oplog.type = 'Boolean';
+            oplog.default = 0;
+        option.log = oplog;
+        
+            mu.key = 'Mu';
+            mu.type = 'Boolean';
+            mu.default = 1;
+        option.mu = mu;
+
+    %% options related to 'SpectralFlux'
+    
+            inc.key = 'Inc';
+            inc.type = 'Boolean';
+            inc.default = 1;
+        option.inc = inc;
+
+            median.key = 'Median';
+            median.type = 'Integer';
+            median.number = 2;
+            median.default = [0 0]; % Not same default as in mirtempo
+        option.median = median;
+
+            hw.key = 'Halfwave';
+            hw.type = 'Boolean';
+            hw.default = 0; %NaN; %0; % Not same default as in mirtempo
+        option.hw = hw;    
+        
+    
+%% options related to mirattackslope
+        slope.type = 'String';
+        slope.choice = {'Diff','Gauss'};
+        slope.default = 'Diff';
+    option.slope = slope;
+    
+%% options related to mirautocor:    
+    
+        enh.key = 'Enhanced';
+        enh.type = 'Integers';
+        enh.default = [];
+        enh.keydefault = 2:10;
+    option.enh = enh;
+    
+        r.key = 'Resonance';
+        r.type = 'String';
+        r.choice = {'ToiviainenSnyder','vonNoorden',0,'off','no'};
+        r.default = 'ToiviainenSnyder';
+    option.r = r;
+        
+        mi.key = 'Min';
+        mi.type = 'Integer';
+        mi.default = 40;
+    option.mi = mi;
+        
+        ma.key = 'Max';
+        ma.type = 'Integer';
+        ma.default = 200;
+    option.ma = ma;    
+
+%% options related to mirtempo:
+
+        sum.key = 'Sum';
+        sum.type = 'String';
+        sum.choice = {'Before','After','Adjacent'};
+        sum.default = 'Before';
+    option.sum = sum;
+    
+        m.key = 'Total';
+        m.type = 'Integer';
+        m.default = 1;
+    option.m = m;
+        
+        thr.key = 'Contrast';
+        thr.type = 'Integer';
+        thr.default = 0.01; % Not same default as in mirtempo
+    option.thr = thr;
+
+specif.option = option;
+
+varargout = mirfunction(@mirpulseclarity,orig,varargin,nargout,specif,@init,@main);
+
+
+
+%% Initialisation
+
+function [x type] = init(x,option)
+%if isframed(x)
+%    warning('WARNING IN MIRPULSECLARITY: The input should not be already decomposed into frames.');
+%    disp(['Suggestion: Use the ''Frame'' option instead.'])
+%end
+if iscell(x)
+    x = x{1};
+end
+if isamir(x,'mirautocor')
+    type = {'mirscalar','mirautocor'};
+elseif length(option.model) > 1
+    a = x;
+    type = {'mirscalar'};
+    for m = 1:length(option.model)
+        if option.frame.length.val
+            y = mirpulseclarity(a,'Model',option.model(m),...
+                                  'Frame',option.frame.length.val,...
+                                          option.frame.length.unit,...
+                                          option.frame.hop.val,...
+                                          option.frame.hop.unit);
+        else
+            y = mirpulseclarity(a,'Model',option.model(m));
+        end
+        if m == 1
+            x = y;
+        else
+            x = x + y;
+        end
+    end
+else
+    if option.model
+        switch option.model
+            case 1
+            case 2
+                option.envmeth = 'Filter';
+                option.fbtype = 'Gammatone';
+                option.mu = 0;
+                option.r = 0;
+                option.lambda = .8;
+                option.sum = 'After';
+        end
+    end
+    if length(option.stratg)>7 && strcmpi(option.stratg(end-6:end),'Autocor')
+        if (strcmpi(option.stratg,'MaxAutocor') || ...
+            strcmpi(option.stratg,'MinAutocor') || ...
+            strcmpi(option.stratg,'EntropyAutocor'))
+            option.m = 0;
+        end
+        if strcmpi(option.stratg,'MinAutocor')
+            option.enh = 0;
+        end
+        if option.frame.length.val
+            [t,x] = mirtempo(x,option.fea,'Method',option.envmeth,...
+                       option.band,...
+                       'Sum',option.sum,'Enhanced',option.enh,...
+                       'Resonance',option.r,'Smooth',option.aver,...
+                       'HalfwaveDiff',option.diffhwr,...
+                       'Lambda',option.lambda,...
+                       'Frame',option.frame.length.val,...
+                               option.frame.length.unit,...
+                               option.frame.hop.val,...
+                               option.frame.hop.unit,...
+                       'FilterbankType',option.fbtype,...
+                       'FilterType',option.ftype,...
+                       'Filterbank',option.fb,'Mu',option.mu,...
+                       'Log',option.log,...
+                       'Inc',option.inc,'Halfwave',option.hw,...
+                       'Median',option.median(1),option.median(2),...
+                       'Min',option.mi,'Max',option.ma,...
+                       'Total',option.m,'Contrast',option.thr);
+        else
+            [t,x] = mirtempo(x,option.fea,'Method',option.envmeth,...
+                       option.band,...
+                       'Sum',option.sum,'Enhanced',option.enh,...
+                       'Resonance',option.r,'Smooth',option.aver,...
+                       'HalfwaveDiff',option.diffhwr,...
+                       'Lambda',option.lambda,...
+                       'FilterbankType',option.fbtype,...
+                       'FilterType',option.ftype,...
+                       'Filterbank',option.fb,'Mu',option.mu,...
+                       'Log',option.log,...
+                       'Inc',option.inc,'Halfwave',option.hw,...
+                       'Median',option.median(1),option.median(2),...
+                       'Min',option.mi,'Max',option.ma,...
+                       'Total',option.m,'Contrast',option.thr);
+        end
+        type = {'mirscalar','mirautocor'};
+    elseif strcmpi(option.stratg,'ExtremEnvelop')
+        x = mironsets(x,'Filterbank',option.fb);
+        type = {'mirscalar','mirenvelope'};
+    elseif strcmpi(option.stratg,'Attack')
+        x = mirattackslope(x,option.slope);
+        type = {'mirscalar','mirenvelope'};
+%    elseif strcmpi(option.stratg,'AttackDiff')
+%        type = {'mirscalar','mirenvelope'};
+    elseif strcmpi(option.stratg,'Articulation')
+        x = mirlowenergy(x,'ASR');
+        type = {'mirscalar','mirscalar'};
+    else
+        type = {'mirscalar','miraudio'};
+    end
+end
+
+
+
+%% Main function
+
+function o = main(a,option,postoption)
+if option.model == 2
+    option.stratg = 'InterfAutocor';
+end
+if isa(a,'mirscalar') && not(strcmpi(option.stratg,'Attack')) % not very nice test... to improve.
+    o = {a};
+    return
+end
+if option.m == 1 && ...
+        (strcmpi(option.stratg,'InterfAutocor') || ...
+         strcmpi(option.stratg,'MeanPeaksAutocor'))
+    option.m = Inf;
+end
+if iscell(a)
+    a = a{1};
+end
+if strcmpi(option.stratg,'MaxAutocor')
+    d = get(a,'Data');
+    rc = mircompute(@max,d);
+elseif strcmpi(option.stratg,'MinAutocor')
+    d = get(a,'Data');
+    rc = mircompute(@minusmin,d);
+elseif strcmpi(option.stratg,'MeanPeaksAutocor')
+    m = get(a,'PeakVal');
+    rc = mircompute(@meanpeaks,m);    
+elseif strcmpi(option.stratg,'KurtosisAutocor')
+    a = mirpeaks(a,'Extract','Total',option.m,'NoBegin','NoEnd');
+    k = mirkurtosis(a);
+    %d = get(k,'Data');
+    %rc = mircompute(@meanpeaks,d);
+    rc = mirmean(k);
+elseif strcmpi(option.stratg,'EntropyAutocor')
+    rc = mirentropy(a);
+elseif strcmpi(option.stratg,'InterfAutocor')
+    a = mirpeaks(a,'Total',option.m,'NoBegin','NoEnd');
+    m = get(a,'PeakVal');
+    p = get(a,'PeakPosUnit');
+    rc = mircompute(@interf,m,p);
+elseif strcmpi(option.stratg,'TempoAutocor')
+    a = mirpeaks(a,'Total',1,'NoBegin','NoEnd');
+    p = get(a,'PeakPosUnit');
+    rc = mircompute(@tempo,p);
+elseif strcmpi(option.stratg,'ExtremEnvelop')
+    a = mirenvelope(a,'Normal');
+    p = mirpeaks(a,'Order','Abscissa');
+    p = get(p,'PeakPreciseVal');
+    n = mirpeaks(a,'Valleys','Order','Abscissa');
+    n = get(n,'PeakPreciseVal');
+    rc = mircompute(@shape,p,n);
+elseif strcmpi(option.stratg,'Attack')
+    rc = mirmean(a);
+%elseif strcmpi(option.stratg,'AttackDiff')
+%    a = mirpeaks(a);
+%    m = get(a,'PeakVal');
+%    rc = mircompute(@meanpeaks,m);    
+elseif strcmpi(option.stratg,'Articulation')
+    rc = a;
+end
+
+if iscell(rc)
+    pc = mirscalar(a,'Data',rc,'Title','Pulse clarity');
+else
+    pc = set(rc,'Title',['Pulse clarity (',get(rc,'Title'),')']);
+end
+
+if option.model
+    switch option.model
+        case 1
+            alpha = 0;
+            beta = 2.2015;
+            lambda = .1;
+        case 2
+            alpha = 0;
+            beta = 3.5982;
+            lambda = 1.87;
+    end
+    if not(lambda == 0)
+        pc = (pc+alpha)^lambda * beta;
+    else
+        pc = log(pc+alpha) * beta;
+    end
+    title = ['Pulse clarity (Model ',num2str(option.model),')'];
+    pc = set(pc,'Title',title);
+end
+
+o = {pc a};
+
+
+%% Routines
+
+function r  = shape(p,n)
+p = p{1};
+n = n{1};
+if length(p)>length(n)
+    d = sum(p(1:end-1) - n) + sum(p(2:end) - n);
+    r  = d/(2*length(n));
+elseif length(p)<length(n)
+    d = sum(p - n(1:end-1)) + sum(p - n(2:end));
+    r  = d/(2*length(p));
+else
+    d = sum(p(2:end) - n(1:end-1)) + sum(p(1:end-1) - n(2:end));
+    r  = d/(2*(length(p)-1));
+end
+
+
+function rc = minusmin(ac)
+rc = -min(ac);
+
+
+function rc = meanpeaks(ac)
+rc = zeros(1,length(ac));
+for j = 1:length(ac)
+    if isempty(ac{j})
+        rc(j) = NaN;
+    else
+        rc(j) = mean(ac{j});
+    end
+end
+
+
+function rc = interf(mk,pk)
+rc = zeros(size(mk));
+for j = 1:size(mk,3)
+    for i = 1:size(mk,2)
+        pij = pk{1,i,j};
+        mij = mk{1,i,j};
+        if isempty(pij)
+            rc(1,i,j) = 0;
+        else
+            high = max(pij(2:end),pij(1));
+            low = min(pij(2:end),pij(1));
+            quo = rem(high,low)./low;
+            nomult = quo>.15 & quo<.85;
+            fij = mij(2:end)/mij(1) .*nomult;
+            fij(fij<0) = 0;
+            rc(1,i,j) = exp(-sum(fij)/4); % Pulsations that are not in integer ratio
+                                          % with dominant pulse decrease clarity
+        end
+    end
+end
+
+
+function rc = tempo(pk)
+rc = zeros(size(pk));
+for j = 1:size(pk,3)
+    for i = 1:size(pk,2)
+        pij = pk{1,i,j};
+        if isempty(pij)
+            rc(1,i,j) = 0;
+        else
+            rc(1,i,j) = exp(-pij(1)/4)/exp(-.33/4); % Fast dominant pulse
+                                                    % increases clarity
+        end
+    end
+end
\ No newline at end of file