diff toolboxes/MIRtoolbox1.3.2/MIRToolbox/mirpeaks.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/mirpeaks.m	Tue Feb 10 15:05:51 2015 +0000
@@ -0,0 +1,1132 @@
+function varargout = mirpeaks(orig,varargin)
+%   p = mirpeaks(x) detect peaks in x.
+%   Optional argument:
+%       mirpeaks(...,'Total',m): only the m highest peaks are selected.
+%           If m=Inf, no limitation of number of peaks.
+%               Default value: m = Inf
+%       mirpeaks(...,'Order',o): specifies the ordering of the peaks.
+%           Possible values for o:
+%               'Amplitude': orders the peaks from highest to lowest
+%                   (Default choice.)
+%               'Abscissa': orders the peaks along the abscissa axis.
+%       mirpeaks(...,'Contrast',cthr): a threshold value. A given local
+%           maximum will be considered as a peak if its distance with the
+%           previous and successive local minima (if any) is higher than 
+%           this threshold. This distance is expressed with respect to the
+%           total amplitude of x: a distance of 1, for instance, is
+%           equivalent to the distance between the maximum and the minimum
+%           of x.
+%               Default value: cthr = 0.1
+%           mirpeaks(...,'SelectFirst',fthr): If the 'Contrast' selection has
+%               been chosen, this additional option specifies that when one
+%               peak has to be chosen out of two candidates, and if the 
+%               difference of their amplitude is below the threshold fthr,
+%               then the most ancien one is selected.
+%               Option toggled off by default:
+%               Default value if toggled on: fthr = cthr/2
+%       mirpeaks(...,'Threshold',thr): a threshold value.
+%           A given local maximum will be considered as a peak if its
+%               normalized amplitude is higher than this threshold. 
+%           A given local minimum will be considered as a valley if its
+%               normalized amplitude is lower than this threshold. 
+%           The normalized amplitude can have value between 0 (the minimum 
+%               of the signal in each frame) and 1 (the maximum in each 
+%               frame).
+%           Default value: thr=0 for peaks thr = 1 for valleys
+%       mirpeaks(...,'Interpol',i): estimates more precisely the peak
+%           position and amplitude using interpolation. Performed only on
+%           data with numerical abscissae axis.
+%           Possible value for i:
+%               '', 'no', 'off', 0: no interpolation
+%               'Quadratic': quadratic interpolation. (default value).
+%       mirpeaks(...,'Valleys'): detect valleys instead of peaks.
+%       mirpeaks(...,'Reso',r): removes peaks whose distance to one or
+%           several higher peaks is lower than a given threshold.
+%           Possible value for the threshold r:
+%               'SemiTone': ratio between the two peak positions equal to
+%                   2^(1/12)
+%               a numerical value : difference between the two peak
+%                   positions equal to that value
+%           When two peaks are distant by an interval lower than the
+%               resolution, the highest of them is selected by default.
+%           mirpeaks(...,'Reso',r,'First') specifies on the contrary that
+%               the first of them is selected by default.
+%       mirpeaks(...,'Nearest',t,s): takes the peak nearest a given abscisse
+%           values t. The distance is computed either on a linear scale
+%           (s = 'Lin') or logarithmic scale (s = 'Log'). In this case,
+%           only one peak is extracted.
+%       mirpeaks(...,'Pref',c,std): indicates a region of preference for
+%           the peak picking, centered on the abscisse value c, with a
+%           standard deviation of std.
+%       mirpeaks(...,'NoBegin'): does not consider the first sample as a
+%           possible peak candidate.
+%       mirpeaks(...,'NoEnd'): does not consider the last sample as a possible
+%           peak candidate.
+%       mirpeaks(...,'Normalize',n): specifies whether frames are
+%           normalized globally or individually.
+%           Possible value for n:
+%               'Global': normalizes the whole frames altogether from 0 to 
+%                   1 (default choice).
+%               'Local': normalizes each frame from 0 to 1.
+%       mirpeaks(...,'Extract'): extracts from the initial curves all the 
+%           positive continuous segments (or "curve portions") where peaks
+%           are located.
+%       mirpeaks(...,'Only'): keeps from the original curve only the data
+%           corresponding to the peaks, and zeroes the remaining data.
+%       mirpeaks(...,'Track',t): tracks temporal continuities of peaks. If
+%           a value t is specified, the variation between successive peaks
+%           is tolerated up to t samples.
+%       mirpeaks(...,'CollapseTrack',ct): collapses tracks into one single
+%           track, and remove small track transitions, of length shorter
+%           than ct samples. Default value: ct = 7
+
+        m.key = 'Total';
+        m.type = 'Integer';
+        m.default = Inf;
+    option.m = m;
+        
+        nobegin.key = 'NoBegin';
+        nobegin.type = 'Boolean';
+        nobegin.default = 0;
+    option.nobegin = nobegin;
+        
+        noend.key = 'NoEnd';
+        noend.type = 'Boolean';
+        noend.default = 0;
+    option.noend = noend;
+        
+        order.key = 'Order';
+        order.type = 'String';
+        order.choice = {'Amplitude','Abscissa'};
+        order.default = 'Amplitude';
+    option.order = order;
+    
+        chro.key = 'Chrono'; % obsolete, corresponds to 'Order','Abscissa'
+        chro.type = 'Boolean';
+        chro.default = 0;
+    option.chro = chro;
+    
+        ranked.key = 'Ranked'; % obsolete, corresponds to 'Order','Amplitude'
+        ranked.type = 'Boolean';
+        ranked.default = 0;
+    option.ranked = ranked;
+        
+        vall.key = 'Valleys';
+        vall.type = 'Boolean';
+        vall.default = 0;
+    option.vall = vall;
+    
+        cthr.key = 'Contrast';
+        cthr.type = 'Integer';
+        cthr.default = .1;
+    option.cthr = cthr;
+        
+        first.key = 'SelectFirst';
+        first.type = 'Integer';
+        first.default = 0;
+        first.keydefault = NaN;
+    option.first = first;
+    
+        thr.key = 'Threshold';
+        thr.type = 'Integer';
+        thr.default = NaN;
+    option.thr = thr;
+            
+        smthr.key = 'MatrixThreshold'; % to be documented in version 1.3
+        smthr.type = 'Integer';
+        smthr.default = NaN;
+    option.smthr = smthr;
+    
+        graph.key = 'Graph';
+        graph.type = 'Integer';
+        graph.default = 0;
+        graph.keydefault = .25;
+    option.graph = graph;
+        
+        interpol.key = 'Interpol';
+        interpol.type = 'String';
+        interpol.default = 'Quadratic';
+        interpol.keydefault = 'Quadratic';
+    option.interpol = interpol;
+    
+        reso.key = 'Reso';
+        %reso.type = 'String';
+        %reso.choice = {0,'SemiTone'};
+        reso.default = 0;
+    option.reso = reso;
+    
+        resofirst.key = 'First';
+        resofirst.type = 'Boolean';
+        resofirst.default = 0;
+    option.resofirst = resofirst;
+        
+        c.key = 'Pref';
+        c.type = 'Integer';
+        c.number = 2;
+        c.default = [0 0];
+    option.c = c;
+        
+        near.key = 'Nearest';
+        near.type = 'Integer';
+        near.default = NaN;
+    option.near = near;
+        
+        logsc.type = 'String';
+        logsc.choice = {'Lin','Log',0};
+        logsc.default = 'Lin';
+    option.logsc = logsc;
+        
+        normal.key = 'Normalize';
+        normal.type = 'String';
+        normal.choice = {'Local','Global'};
+        normal.default = 'Global';
+    option.normal = normal;
+
+        extract.key = 'Extract';
+        extract.type = 'Boolean';
+        extract.default = 0;
+    option.extract = extract;
+    
+        only.key = 'Only';
+        only.type = 'Boolean';
+        only.default = 0;
+    option.only = only;
+
+        delta.key = 'Track';
+        delta.type = 'Integer';
+        delta.default = 0;
+        delta.keydefault = Inf;
+    option.delta = delta;
+    
+        mem.key = 'TrackMem';
+        mem.type = 'Integer';
+        mem.default = Inf;
+    option.mem = mem;
+
+        shorttrackthresh.key = 'CollapseTracks';
+        shorttrackthresh.type = 'Integer';
+        shorttrackthresh.default = 0;
+        shorttrackthresh.keydefault = 7;
+    option.shorttrackthresh = shorttrackthresh;
+
+        scan.key = 'ScanForward'; % specific to mironsets(..., 'Klapuri99')
+        scan.default = [];
+    option.scan = scan;
+    
+specif.option = option;
+
+varargout = mirfunction(@mirpeaks,orig,varargin,nargout,specif,@init,@main);
+
+
+function [x type] = init(x,option)
+type = mirtype(x);
+
+
+function p = main(x,option,postoption)
+if iscell(x)
+    x = x{1};
+end
+if option.chro
+    option.order = 'Abscissa';
+elseif option.ranked
+    option.order = 'Amplitude';
+end
+if not(isnan(option.near)) && option.m == 1
+    option.m = Inf;
+end
+x = purgedata(x);
+if option.m <= 0
+    p = x;
+    return
+end
+d = get(x,'Data');
+sr = get(x,'Sampling');
+cha = 0; % Indicates when it is possible to represent as a curve along the 
+         % Z-axis (channels) instead of the X-axis (initial abscissa).
+if isnan(option.first)
+    option.first = option.cthr / 2;
+end
+if isa(x,'mirscalar')
+    t = get(x,'FramePos');
+    for i = 1:length(d)
+        for j = 1:length(d{i})
+            d{i}{j} = d{i}{j}';
+            if size(t{i},1) == 1
+                t{i}{j} = t{i}{j}(1,:,:)';
+            else
+                t{i}{j} = (t{i}{j}(1,:,:)+t{i}{j}(2,:,:))'/2;
+            end
+        end
+    end
+elseif isa(x,'mirsimatrix')
+    t = get(x,'FramePos');
+    for i = 1:length(t)
+        for j = 1:length(t{i})
+            t{i}{j} = repmat((t{i}{j}(1,:,:)+t{i}{j}(2,:,:))'/2,...
+                                    [1 size(d{i}{j},2) 1]);
+        end
+    end
+elseif isa(x,'mirhisto')
+    error('ERROR IN MIRPEAKS: peaks of histogram not considered yet.');
+else
+    for i = 1:length(d)
+        for j = 1:length(d{i})
+            if iscell(d{i})
+                dij = d{i}{j};
+                if ~cha && j == 1 && size(dij,3) > 1 && size(dij,1) == 1
+                    cha = 1;
+                end
+                if cha && j > 1 && size(dij,1) > 1
+                    cha = -1;
+                end
+            end
+        end
+        for j = 1:length(d{i})
+            if iscell(d{i})
+                dij = d{i}{j};
+                if cha == 1
+                    if iscell(dij)
+                        for k = 1:size(dij,2)
+                            d{i}{j}{k} = reshape(dij{k},size(dij{k},2),size(dij{k},3));
+                            d{i}{j}{k} = d{i}{j}{k}';
+                        end
+                    else
+                        d{i}{j} = reshape(dij,size(dij,2),size(dij,3));
+                        d{i}{j} = d{i}{j}';
+                    end
+                end
+            end
+        end
+    end
+    if cha == 1
+        t = get(x,'Channels');
+    else
+        t = get(x,'Pos');
+    end
+end
+pp = cell(1,length(d));
+pv = cell(1,length(d));
+pm = cell(1,length(d));
+ppp = cell(1,length(d));
+ppv = cell(1,length(d));
+tp = cell(1,length(d));
+tv = cell(1,length(d));
+
+if isnan(option.thr)
+    option.thr = 0;
+else
+    if option.vall
+        option.thr = 1-option.thr;
+    end
+end
+%if isnan(option.lthr)
+%    option.lthr = 1;
+%else
+%    if option.vall
+%        option.lthr = 1-option.lthr;
+%    end
+%end
+if isnan(option.smthr)
+    option.smthr = option.thr - .2;
+end
+
+if not(isempty(option.scan))
+    pscan = get(option.scan,'PeakPos');
+end
+
+interpol = get(x,'Interpolable') && not(isempty(option.interpol)) && ...
+                ((isnumeric(option.interpol) && option.interpol) || ...
+                 (ischar(option.interpol) && not(strcmpi(option.interpol,'No')) && not(strcmpi(option.interpol,'Off'))));
+                
+for i = 1:length(d) % For each audio file,...
+    di = d{i};
+    if cha == 1
+        ti = t; %sure ?
+    else
+        ti = t{i};
+    end
+    if not(iscell(di))
+        di = {di};
+        if isa(x,'mirchromagram') && not(cha)
+            ti = {ti};
+        end
+    end
+    for h = 1:length(di)    % For each segment,...
+        dh0 = di{h};
+        if option.vall
+            dh0 = -dh0;
+        end
+        dh2 = dh0;
+        [nl0 nc np nd0] = size(dh0);
+        if cha == 1
+            if iscell(ti)
+                %% problem here!!!
+                ti = ti{i}; %%%%%it seems that sometimes we need to use instead ti{i}(:);
+            end
+            th = repmat(ti,[1,nc,np,nd0]);
+        else
+            th = ti{h};
+            if iscell(th)  % Non-numerical abscissae are transformed into numerical ones. 
+                th = repmat((1:size(th,1))',[1,nc,np]);
+            else
+                if size(th,3)<np
+                    th = repmat(th,[1,1,np]);
+                end
+            end
+        end
+        if option.c    % If a prefered region is specified, the data is amplified accordingly
+            dh0 = dh0.*exp(-(th-option.c(1)).^2/2/option.c(2)^2)...
+                                    /option.c(2)/sqrt(2*pi)/2;
+        end
+
+        % Now the data is rescaled. the minimum is set to 0
+        % and the maximum to 1.
+        state = warning('query','MATLAB:divideByZero');
+        warning('off','MATLAB:divideByZero');
+        
+        % Let's first normalize all frames globally:
+        dh0 = (dh0-repmat(min(min(min(dh0,[],1),[],2),[],4),[nl0 nc 1 nd0]))./...
+            repmat(max(max(max(dh0,[],1),[],2),[],4)...
+                  -min(min(min(dh0,[],1),[],2),[],4),[nl0 nc 1 nd0]);
+        for l = 1:nd0 
+            [unused lowc] = find(max(dh0(:,:,:,l))<option.thr);
+            dh0(:,lowc,1,l) = 0;
+        end
+        
+        if strcmpi(option.normal,'Local')
+            % Normalizing each frame separately:
+            dh0 = (dh0-repmat(min(min(dh0,[],1),[],4),[nl0 1 1 nd0]))./... 
+                repmat(max(max(dh0,[],1),[],4)...
+                      -min(min(dh0,[],1),[],4),[nl0 1 1 nd0]);
+        end
+        warning(state.state,'MATLAB:divideByZero');
+
+        if option.nobegin
+            dh0 = [Inf(1,nc,np,nd0);dh0];   
+            % This infinite value at the beginning
+            % prevents the selection of the first sample of data
+            dh2 = [Inf(1,nc,np,nd0);dh2];
+            th = [NaN(1,nc,np,1);th];
+        else
+            dh0 = [-Inf(1,nc,np,nd0);dh0];
+            % This infinite negative value at the beginning
+            % ensures the selection of the first sample of data
+            dh2 = [-Inf(1,nc,np,nd0);dh2];
+            th = [NaN(1,nc,np,1);th];
+        end
+        if option.noend
+            dh0 = [dh0;Inf(1,nc,np,nd0)];
+            % idem for the last sample of data
+            dh2 = [dh2;Inf(1,nc,np,nd0)];
+            th = [th;NaN(1,nc,np,1)];
+        else
+            dh0 = [dh0;-Inf(1,nc,np,nd0)];
+            dh2 = [dh2;-Inf(1,nc,np,nd0)];
+            th = [th;NaN(1,nc,np,1)];
+        end
+        nl0 = nl0+2;
+
+        % Rearrange the 4th dimension (if used) into the 1st one.
+        nl = nl0*nd0;
+        dh = zeros(nl,nc,np);
+        dh3 = zeros(nl,nc,np);
+        th2 = zeros(nl,nc,np);
+        for l = 1:nd0
+            dh((l-1)*nl0+(1:nl0)',:,:) = dh0(:,:,:,l);
+            dh3((l-1)*nl0+(1:nl0)',:,:) = dh2(:,:,:,l);
+            th2((l-1)*nl0+(1:nl0)',:,:) = th(:,:,:);
+        end
+        
+        th = th2; % The X-abscissa
+
+        ddh = diff(dh);
+        % Let's find the local maxima
+        for l = 1:np
+            dl = dh(2:end-1,:,l);
+            for k = 1:nc
+                dk = dl(:,k);
+                mx{1,k,l} = find(and(and(dk >= option.cthr, ...
+                                         dk >= option.thr),...     
+                                         ... dk <= option.lthr)),
+                                     and(ddh(1:(end-1),k,l) > 0, ...
+                                         ddh(2:end,k,l) <= 0)))+1;
+            end
+        end
+        if option.cthr
+            for l = 1:np
+                for k = 1:nc
+                    finalmxk = [];
+                    mxk = mx{1,k,l};
+                    if not(isempty(mxk))
+                        wait = 0;
+                        if length(mxk)>5000
+                            wait = waitbar(0,['Selecting peaks... (0 out of 0)']);
+                        end
+                        %if option.m < Inf
+                        %    [unused,idx] = sort(dh(mxk,k,l),'descend'); % The peaks are sorted in decreasing order
+                        %    mxk = mxk(sort(idx(1:option.m)));
+                        %end
+                        j = 1;  % Scans the peaks from begin to end.
+                        mxkj = mxk(j); % The current peak
+                        jj = j+1;
+                        bufmin = Inf;
+                        bufmax = dh(mxkj,k,l);
+                        oldbufmin = min(dh(1:mxk(1)-1,k,l));
+                        while jj <= length(mxk)
+                            if wait && not(mod(jj,5000))
+                                waitbar(jj/length(mxk),wait,['Selecting peaks... (',num2str(length(finalmxk)),' out of ',num2str(jj),')']);
+                            end
+                            bufmin = min(bufmin, ...
+                                min(dh(mxk(jj-1)+1:mxk(jj)-1,k,l)));
+                            if bufmax - bufmin < option.cthr
+                                % There is no contrastive notch
+                                if dh(mxk(jj),k,l) > bufmax && ...
+                                        (dh(mxk(jj),k,l) - bufmax > option.first ...
+                                        || (bufmax - oldbufmin < option.cthr))
+                                    % If the new peak is significantly
+                                    % higher than the previous one,
+                                    % The peak is transfered to the new
+                                    % position
+                                    j = jj;
+                                    mxkj = mxk(j); % The current peak
+                                    bufmax = dh(mxkj,k,l);
+                                    oldbufmin = min(oldbufmin,bufmin);
+                                    bufmin = Inf;
+                                elseif dh(mxk(jj),k,l) - bufmax <= option.first
+                                    bufmax = max(bufmax,dh(mxk(jj),k,l));
+                                    oldbufmin = min(oldbufmin,bufmin);
+                                end
+                            else
+                                % There is a contrastive notch
+                                if bufmax - oldbufmin < option.cthr
+                                    % But the previous peak candidate
+                                    % is too weak and therefore
+                                    % discarded
+                                    oldbufmin = min(oldbufmin,bufmin);
+                                else
+                                    % The previous peak candidate is OK
+                                    % and therefore stored
+                                    finalmxk(end+1) = mxkj;
+                                    oldbufmin = bufmin;
+                                end
+                                bufmax = dh(mxk(jj),k,l);
+                                j = jj;
+                                mxkj = mxk(j); % The current peak
+                                bufmin = Inf;
+                            end
+                            jj = jj+1;
+                        end
+                        if bufmax - oldbufmin >= option.cthr && ...
+                                bufmax - min(dh(mxk(j)+1:end,k,l)) >= option.cthr
+                            % The last peak candidate is OK and stored
+                            finalmxk(end+1) = mxk(j);
+                        end
+                        if wait
+                            waitbar(1,wait);
+                            close(wait);
+                            drawnow
+                        end
+                    end
+                    mx{1,k,l} = finalmxk;
+                end
+            end
+        end
+        if not(isempty(option.scan)) % 'ScanForward' option, used for 'Klapuri99' in mironsets
+            for l = 1:np
+                for k = 1:nc   
+                    pscankl = pscan{i}{h}{1,k,l}; % scan seed positions
+                    mxkl = [];
+                    lp = length(pscankl); % number of peaks
+                    for jj = 1:lp         % for each peak
+                        fmx = find(mx{1,k,l}>pscankl(jj),1);
+                            % position of the next max following the
+                            % current seed
+                        fmx = mx{1,k,l}(fmx);
+                        if jj<lp && (isempty(fmx) || fmx>=pscankl(jj+1))
+                            [unused fmx] = max(dh(pscankl(jj):...
+                                                  pscankl(jj+1)-1,k,l));
+                            fmx = fmx+pscankl(jj)-1;
+                        elseif jj==lp && isempty(fmx)
+                            [unused fmx] = max(dh(pscankl(jj):end,k,l));
+                            fmx = fmx+pscankl(jj)-1;
+                        end
+                        mxkl = [mxkl fmx];
+                    end
+                    mx{1,k,l} = mxkl;
+                end
+            end
+        end
+        if not(isequal(option.reso,0)) % Removing peaks too close to higher peaks
+            if ischar(option.reso) && strcmpi(option.reso,'SemiTone')
+                compar = @semitone_compar;
+            elseif isnumeric(option.reso)
+                compar = @dist_compar;
+            end
+            for l = 1:np
+                for k = 1:nc
+                    mxlk = sort(mx{1,k,l});
+                    j = 1;
+                    while j < length(mxlk)-1
+                        if compar(th(mxlk(j+1),k,l),th(mxlk(j),k,l),option.reso)
+                            decreas = option.resofirst || ...
+                                dh(mxlk(j+1),k,l)<dh(mxlk(j),k,l);
+                            mxlk(j + decreas) = [];
+                        else
+                            j = j+1;
+                        end
+                    end
+                    if length(mxlk)>1 && compar(th(mxlk(end),k,l),...
+                                                 th(mxlk(end-1),k,l),...
+                                                 option.reso)
+                        decreas = not(option.resofirst) &&...
+                            dh(mxlk(end),k,l)>dh(mxlk(end-1),k,l);
+                        mxlk(end-decreas) = [];
+                    end
+                    mx{1,k,l} = mxlk;
+                end
+            end
+        end
+        if not(isnan(option.near)) % Finding a peak nearest a given prefered location
+            for l = 1:np
+                for k = 1:nc
+                    mxlk = mx{1,k,l};
+                    if strcmp(option.logsc,'Log')
+                        [M I] = min(abs(log(th(mxlk,k,l)/option.near)));
+                    else
+                        [M I] = min(abs(th(mxlk,k,l)-option.near));
+                    end
+                    mx{1,k,l} = mxlk(I);
+                end
+            end
+        end
+        if option.delta % Peak tracking
+            tp{i}{h} = cell(1,np);
+            if interpol
+                tpp{i}{h} = cell(1,np);
+                tpv{i}{h} = cell(1,np);
+            end
+            for l = 1:np
+                
+                % mxl will be the resulting track position matrix
+                % and myl the related track amplitude
+                % In the first frame, tracks can be identified to peaks.
+                mxl = mx{1,1,l}(:)-1;        
+                myl = dh(mx{1,1,l}(:),k,l); 
+                
+                % To each peak is associated the related track ID
+                tr2 = 1:length(mx{1,1,l});
+                
+                grvy = []; % The graveyard...
+                
+                wait = 0;
+                if nc-1>500
+                    wait = waitbar(0,['Tracking peaks...']);
+                end
+
+                for k = 1:nc-1
+                    % For each successive frame...
+                    
+                    if not(isempty(grvy))
+                        old = find(grvy(:,2) == k-option.mem-1);
+                        grvy(old,:) = [];
+                    end
+                    
+                    if wait && not(mod(k,100))
+                        waitbar(k/(nc-1),wait);
+                    end
+
+                    mxk1 = mx{1,k,l};   % w^k
+                    mxk2 = mx{1,k+1,l}; % w^{k+1}
+                    thk1 = th(mxk1,k,l);
+                    thk2 = th(mxk2,k,l);
+                    myk2 = dh(mx{1,k+1,l},k,l); % amplitude
+                    tr1 = tr2;
+                    tr2 = NaN(1,length(mxk2));
+                    
+                    mxl(:,k+1) = mxl(:,k);
+                                        
+                    if isempty(thk1) || isempty(thk2)
+                        %% IS THIS TEST NECESSARY??
+                        
+                        myl(:,k+1) = 0;
+                    else
+                        for n = 1:length(mxk1)
+                            % Let's check each track.
+                            tr = tr1(n); % Current track.
+
+                            if not(isnan(tr))
+                                % still alive...
+
+                                % Step 1 in Mc Aulay & Quatieri
+                                [int m] = min(abs(thk2-thk1(n)));
+                                if isinf(int) || int > option.delta
+                                    % all w^{k+1} outside matching interval:
+                                        % partial becomes dead
+                                    mxl(tr,k+1) = mxl(tr,k);
+                                    myl(tr,k+1) = 0;
+                                    grvy = [grvy; tr k]; % added to the graveyard
+                                else
+                                    % closest w^{k+1} is tentatively selected:
+                                        % candidate match
+
+                                    % Step 2 in Mc Aulay & Quatieri
+                                    [best mm] = min(abs(thk2(m)-th(mx{1,k,l})));
+                                    if mm == n
+                                        % no better match to remaining w^k:
+                                            % definite match
+                                        mxl(tr,k+1) = mxk2(m)-1;
+                                        myl(tr,k+1) = myk2(m);
+                                        tr2(m) = tr;
+                                        thk1(n) = -Inf; % selected w^k is eliminated from further consideration
+                                        thk2(m) = Inf;  % selected w^{k+1} is eliminated as well
+                                        if not(isempty(grvy))
+                                            zz = find ((mxl(grvy(:,1),k) >= mxl(tr,k) & ...
+                                                        mxl(grvy(:,1),k) <= mxl(tr,k+1)) | ...
+                                                       (mxl(grvy(:,1),k) <= mxl(tr,k) & ...
+                                                        mxl(grvy(:,1),k) >= mxl(tr,k+1)));
+                                            grvy(zz,:) = [];
+                                        end
+                                    else
+                                        % let's look at adjacent lower w^{k+1}...
+                                        [int mmm] = min(abs(thk2(1:m)-thk1(n)));
+                                        if int > best || ... % New condition added (Lartillot 16.4.2010)
+                                                isinf(int) || ... % Conditions proposed in Mc Aulay & Quatieri (all w^{k+1} below matching interval)
+                                                int > option.delta
+                                                % partial becomes dead
+                                            mxl(tr,k+1) = mxl(tr,k);
+                                            myl(tr,k+1) = 0;
+                                            grvy = [grvy; tr k]; % added to the graveyard
+                                        else
+                                            % definite match
+                                            mxl(tr,k+1) = mxk2(mmm)-1;
+                                            myl(tr,k+1) = myk2(mmm);
+                                            tr2(mmm) = tr;
+                                            thk1(n) = -Inf;     % selected w^k is eliminated from further consideration
+                                            thk2(mmm) = Inf;    % selected w^{k+1} is eliminated as well
+                                            if not(isempty(grvy))
+                                                zz = find ((mxl(grvy(:,1),k) >= mxl(tr,k) & ...
+                                                            mxl(grvy(:,1),k) <= mxl(tr,k+1)) | ...
+                                                           (mxl(grvy(:,1),k) <= mxl(tr,k) & ...
+                                                            mxl(grvy(:,1),k) >= mxl(tr,k+1)));
+                                                grvy(zz,:) = [];
+                                            end
+                                        end
+                                    end
+                                end
+                            end
+                        end
+                    end
+                    
+                    % Step 3 in Mc Aulay & Quatieri
+                    for m = 1:length(mxk2)
+                        if not(isinf(thk2(m)))
+                            % unmatched w^{k+1}
+                            
+                            if isempty(grvy)
+                                int = [];
+                            else
+                                % Let's try to reuse a zombie from the
+                                % graveyard (Lartillot).
+                                [int z] = min(abs(th(mxl(grvy(:,1),k+1)+1,k,l)-thk2(m)));
+                            end
+                            if isempty(int) || int > option.delta ...
+                                    || int > min(abs(th(mxl(:,k+1)+1,k,l)-thk2(m)))
+                                % No suitable zombie.
+                                % birth of a new partial (Mc Aulay &
+                                % Quatieri)
+                                mxl = [mxl;zeros(1,k+1)];
+                                tr = size(mxl,1);
+                                mxl(tr,k) = mxk2(m)-1;
+                            else
+                                % Suitable zombie found. (Lartillot)
+                                tr = grvy(z,1);
+                                grvy(z,:) = [];
+                            end
+                            mxl(tr,k+1) = mxk2(m)-1;
+                            myl(tr,k+1) = myk2(m);
+                            tr2(m) = tr;
+                        end
+                    end
+                end
+                
+                if wait
+                    waitbar(1,wait);
+                    close(wait);
+                    drawnow
+                end
+
+                if size(mxl,1) > option.m
+                    tot = sum(myl,2);
+                    [tot ix] = sort(tot,'descend');
+                    mxl(ix(option.m+1:end),:) = [];
+                    myl(ix(option.m+1:end),:) = [];
+                end
+                
+                mxl(:,not(max(myl))) = 0;
+                
+                if option.shorttrackthresh
+                    [myl bestrack] = max(myl,[],1);
+                    mxl = mxl(bestrack + (0:size(mxl,2)-1)*size(mxl,1));
+                    changes = find(not(bestrack(1:end-1) == bestrack(2:end)))+1;
+                    if not(isempty(changes))
+                        lengths = diff([1 changes nc+1]);
+                        shorts = find(lengths < option.shorttrackthresh);
+                        for k = 1:length(shorts)
+                            if shorts(k) == 1
+                                k1 = 1;
+                            else
+                                k1 = changes(shorts(k)-1);
+                            end
+                            k2 = k1 + lengths(shorts(k)) -1;
+                            myl(1,k1:k2) = 0;
+                            mxl(1,k1:k2) = 0;
+                        end
+                    end
+                end
+                
+                tp{i}{h}{l} = mxl;
+                tv{i}{h}{l} = myl;
+                
+                if interpol  
+                    tpv{i}{h}{l} = zeros(size(mxl));
+                    tpp{i}{h}{l} = zeros(size(mxl));
+                    for k = 1:size(mxl,2)
+                        for j = 1:size(mxl,1)
+                            mj = mxl(j,k);
+                            if mj>2 && mj<size(dh3,1)-1
+                                % More precise peak position
+                                y0 = dh3(mj,k,l);
+                                ym = dh3(mj-1,k,l);
+                                yp = dh3(mj+1,k,l);
+                                p = (yp-ym)/(2*(2*y0-yp-ym));
+                                tpv{i}{h}{l}(j,k) = y0 - 0.25*(ym-yp)*p;
+                                if p >= 0
+                                    tpp{i}{h}{l}(j,k) = (1-p)*th(mj,k,l)+p*th(mj+1,k,l);
+                                elseif p < 0
+                                    tpp{i}{h}{l}(j,k) = (1+p)*th(mj,k,l)-p*th(mj-1,k,l);
+                                end
+                            elseif mj
+                                tpv{i}{h}{l}(j,k) = dh3(mj,k,l);
+                                tpp{i}{h}{l}(j,k) = th(mj,k,l);
+                            end
+                        end
+                    end
+                end
+            end
+        end
+        if isa(x,'mirsimatrix') && option.graph
+            % Finding the best branch inside a graph constructed out of a
+            % similarity matrix
+            g{i}{h} = cell(1,nc,np);
+                % Branch info related to each peak
+            br{i}{h} = {};
+                % Info related to each branch
+            scog{i}{h} = cell(1,nc,np);
+                % Score related to each peak
+            scob{i}{h} = [];
+                % Score related to each branch
+            for l = 1:np
+                wait = waitbar(0,['Creating peaks graph...']);
+                for k = 1:nc
+                    g{i}{h}{1,k,l} = cell(size(mx{1,k,l}));
+                    scog{i}{h}{1,k,l} = zeros(size(mx{1,k,l}));
+                    if wait && not(mod(k,50))
+                        waitbar(k/(nc-1),wait);
+                    end
+                    mxk = mx{1,k,l}; % Peaks in current frame
+                    for j = k-1:-1:max(1,k-100) % Recent frames
+                        mxj = mx{1,j,l};        % Peaks in one recent frame
+                        for kk = 1:length(mxk)
+                            mxkk = mxk(kk);     % For each of current peaks
+                            for jj = 1:length(mxj)
+                                mxjj = mxj(jj); % For each of recent peaks
+                                sco = k-j - abs(mxkk-mxjj);
+                                    % Crossprogression from recent to
+                                    % current peak
+                                if sco >= 0 
+                                        % Negative crossprogression excluded
+                                    dist = 0;
+                                    % The distance between recent and
+                                    % current peak is the sum of all the
+                                    % simatrix values when joining the two
+                                    % peaks with a straight line.
+                                    for m = j:k
+                                        % Each point in that straight line.
+                                        mxm = mxjj + (mxkk-mxjj)*(m-j)/(k-j);
+                                        if mxm == floor(mxm)
+                                            dist = dist + 1-dh(mxm,m,l);
+                                        else
+                                            dhm0 = dh(floor(mxm),m,l);
+                                            dhm1 = dh(ceil(mxm),m,l);
+                                            dist = dist + 1-...
+                                                (dhm0 + ...
+                                                 (dhm1-dhm0)*(mxm-floor(mxm)));
+                                        end
+                                        if dist > option.graph
+                                            break
+                                        end
+                                    end
+                                    if dist < option.graph
+                                        % If the distance between recent
+                                        % and current peak is not too high,
+                                        % a new edge is formed between the
+                                        % peaks, and added to the graph.
+                                        gj = g{i}{h}{1,j,l}{jj};
+                                            % Branch information associated
+                                            % with recent peak
+                                        gk = g{i}{h}{1,k,l}{kk};
+                                            % Branch information associated
+                                            % with current peak
+                                        if isempty(gk) || ...
+                                                sco > scog{i}{h}{1,k,l}(kk)
+                                            % Current peak branch to be updated
+                                            if isempty(gj)
+                                                % New branch starting
+                                                % from scratch
+                                                newsco = sco;
+                                                scob{i}{h}(end+1) = newsco;
+                                                bid = length(scob{i}{h});
+                                                g{i}{h}{1,j,l}{jj} = ...
+                                                    [k kk bid newsco];
+                                                br{i}{h}{bid} = [j jj;k kk];
+                                            else
+                                                newsco = scog{i}{h}{1,j,l}(jj)+sco;
+                                                if length(gj) == 1
+                                                    % Recent peak not
+                                                    % associated with other
+                                                    % branch
+                                                    % -> Branch extension
+                                                    bid = gj;
+                                                    g{i}{h}{1,j,l}{jj} = ...
+                                                        [k kk bid newsco];
+                                                    br{i}{h}{bid}(end+1,:) = [k kk];
+                                                else
+                                                    % Recent peak already
+                                                    % associated with other
+                                                    % branch
+                                                    % -> Branch fusion
+                                                    bid = length(scob{i}{h})+1;
+                                                    g{i}{h}{1,j,l}{jj} = ...
+                                                        [k kk bid newsco; gj];
+                                                    other = br{i}{h}{gj(1,3)};
+                                                        % Other branch
+                                                        % info
+                                                        % Let's copy its
+                                                        % prefix to the new
+                                                        % branch:
+                                                    other(other(:,1)>j,:) = [];
+                                                    br{i}{h}{bid} = [other;k kk];
+                                                end
+                                                scob{i}{h}(bid) = newsco;
+                                            end
+                                            g{i}{h}{1,k,l}{kk} = bid;
+                                                % New peak associated with
+                                                % branch
+                                            scog{i}{h}{1,k,l}(kk) = newsco;
+                                        end
+                                    end
+                                end
+                            end
+                        end
+                    end
+                end
+                [scob{i}{h} IX] = sort(scob{i}{h},'descend');
+                    % Branch are ordered from best score to lowest
+                br{i}{h} = br{i}{h}(IX);
+                if wait
+                    waitbar(1,wait);
+                    close(wait);
+                    drawnow
+                end
+            end
+        end
+        for l = 1:np % Orders the peaks and select the best ones
+            for k = 1:nc
+                mxk = mx{1,k,l};
+                if length(mxk) > option.m 
+                    [unused,idx] = sort(dh(mxk,k,l),'descend');
+                    idx = idx(1:option.m);
+                elseif strcmpi(option.order,'Amplitude')
+                    [unused,idx] = sort(dh(mxk,k,l),'descend');
+                else
+                    idx = 1:length(dh(mxk,k,l));
+                end
+                if strcmpi(option.order,'Abscissa')
+                    mx{1,k,l} = sort(mxk(idx));
+                elseif strcmpi(option.order,'Amplitude')
+                    mx{1,k,l} = mxk(idx);
+                end
+            end
+        end
+        if option.extract % Extracting the positive part of the curve containing the peaks
+            if isa(x,'mirtemporal')
+                filn = floor(sr{i}/25);
+            else
+                filn = 10;
+            end
+            if filn>1 && size(dh3,1)>5
+                filn = min(filn,floor(size(dh3,1)/3));
+                fild = filtfilt(ones(1,filn)/2,1,dh3(2:end-1,:,:))/filn/2;
+            else
+                fild = dh3(2:end-1,:,:);
+            end
+            fild = [zeros(1,size(fild,2),size(fild,3));diff(fild)];
+            for l = 1:np
+                for k = 1:nc
+                    idx = 1:size(dh,1);
+                    mxlk = sort(mx{1,k,l}-1);
+                    for j = 1:length(mxlk)
+                        
+                        if fild(mxlk(j),k,l) < 0
+                            bef0 = find(fild(1:mxlk(j)-1,k,l)>=0);
+                            if isempty(bef0)
+                                bef0 = [];
+                            end
+                        else
+                            bef0 = mxlk(j)-1;
+                        end
+                        if isempty(bef0)
+                            bef = 0;
+                        else
+                            bef = find(fild(1:bef0(end),k,l)<=0);
+                            if isempty(bef)
+                                bef = 0;
+                            end
+                        end
+                        if j>1 && bef(end)<aft(1)+2
+                            idx(mxlk(j-1):mxlk(j)) = 0;
+                            [unused btw] = min(dh3(mxlk(j-1)+1:mxlk(j)+1,k,l));
+                            btw = btw+mxlk(j-1);
+                            idx(btw-2:btw+2) = btw-2:btw+2;
+                            bef = btw+2;
+                        end
+                        
+                        if fild(mxlk(j),k,l) > 0
+                            aft0 = find(fild(mxlk(j)+1:end,k,l)<=0)+mxlk(j);
+                            if isempty(aft0)
+                                aft0 = [];
+                            end
+                        else
+                            aft0 = mxlk(j)+1;
+                        end
+                        if isempty(aft0)
+                            aft = size(d{i}{h},1)+1;
+                        else
+                            aft = find(fild(aft0(1):end,k,l)>=0)+mxlk(j);
+                            if isempty(aft)
+                                aft = size(d{i}{h},1)+1;
+                            end
+                        end
+                        
+                        idx(bef(end)+3:aft(1)-3) = 0;
+                    end
+                    idx = idx(find(idx));
+                    dh3(idx,k,l) = NaN;
+                end
+            end
+        end
+        if option.vall
+            dh3 = -dh3;
+        end
+        mmx = cell(1,nc,np);
+        mmy = cell(1,nc,np);
+        mmv = cell(1,nc,np);
+        for l = 1:np
+            for k = 1:nc
+                mmx{1,k,l} = mod(mx{1,k,l}(:,:,1),nl0)-1;
+                mmy{1,k,l} = ceil(mx{1,k,l}/nl0);
+                mmv{1,k,l} = dh3(mx{1,k,l}(:,:,1),k,l);
+            end
+        end
+        pp{i}{h} = mmx;
+        pm{i}{h} = mmy;
+        pv{i}{h} = mmv;
+        if not(interpol)
+            ppp{i}{h} = {};
+            ppv{i}{h} = {};
+        else % Interpolate to find the more exact peak positions
+            pih = cell(1,nc,np);
+            vih = cell(1,nc,np);
+            for l = 1:np
+                for k = 1:nc
+                    mxlk = mx{1,k,l};
+                    vih{1,k,l} = zeros(length(mxlk),1);
+                    pih{1,k,l} = zeros(length(mxlk),1);
+                    for j = 1:length(mxlk)
+                        mj = mxlk(j); % Current values
+                        if strcmpi(option.interpol,'quadratic')
+                            if mj>2 && mj<length(dh3)-1
+                                % More precise peak position
+                                y0 = dh3(mj,k,l);
+                                ym = dh3(mj-1,k,l);
+                                yp = dh3(mj+1,k,l);
+                                p = (yp-ym)/(2*(2*y0-yp-ym));
+                                vih{1,k,l}(j) = y0 - 0.25*(ym-yp)*p;
+                                if p >= 0
+                                    pih{1,k,l}(j) = (1-p)*th(mj,k,l)+p*th(mj+1,k,l);
+                                elseif p < 0
+                                    pih{1,k,l}(j) = (1+p)*th(mj,k,l)-p*th(mj-1,k,l);
+                                end
+                            else
+                                vih{1,k,l}(j) = dh3(mj,k,l);
+                                pih{1,k,l}(j) = th(mj,k,l);
+                            end
+                        end
+                    end
+                end
+            end
+            ppp{i}{h} = pih;
+            ppv{i}{h} = vih;
+        end
+        if not(iscell(d{i})) % for chromagram
+            d{i} = dh3(2:end-1,:,:,:);
+        else
+            if cha == 1
+                d{i}{h} = zeros(1,size(dh3,2),size(dh3,1)-2);
+                for k = 1:size(dh3,2)
+                     d{i}{h}(1,k,:) = dh3(2:end-1,k);
+                end
+            else
+                d{i}{h} = dh3(2:end-1,:,:,:);
+            end
+        end
+        if option.only
+            dih = zeros(size(d{i}{h}));
+            for l = 1:np
+                for k = 1:nc
+                    dih(pp{i}{h}{1,k,l},k,l) = ...
+                        d{i}{h}(pp{i}{h}{1,k,l},k,l);
+                end
+            end
+            d{i}{h} = dih;
+        end
+    end
+end
+p = set(x,'PeakPos',pp,'PeakVal',pv,'PeakMode',pm);
+if interpol
+   p = set(p,'PeakPrecisePos',ppp,'PeakPreciseVal',ppv);
+end
+if option.extract
+    p = set(p,'Data',d);
+end
+empty = cell(1,length(d));
+if option.only
+    p = set(p,'Data',d,'PeakPos',empty,'PeakVal',empty,'PeakMode',empty);
+end
+if option.delta
+    p = set(p,'TrackPos',tp,'TrackVal',tv);
+    if interpol
+       p = set(p,'TrackPrecisePos',tpp,'TrackPreciseVal',tpv);
+    end
+end
+if isa(x,'mirsimatrix') && option.graph
+    p = set(p,'Graph',g,'Branch',br);
+end
+
+
+function y = semitone_compar(p1,p2,thres)
+y = p1/p2 < 2^(1/12);
+
+
+function y = dist_compar(p1,p2,thres)
+y = p1-p2 < thres;
\ No newline at end of file