Code covered by the BSD License  

Highlights from
MIRtoolbox

image thumbnail
from MIRtoolbox by Olivier Lartillot
An innovative environment, on top of Matlab, for music and audio analysis

mirstat(f,varargin)
function varargout = mirstat(f,varargin)
% stat = mirstat(f) returns basic statistics of the feature f as a
%   structure array stat such that:
%       stat.Mean is the mean of the feature;
%       stat.Std is the standard deviation;
%       stat.Slope is the linear slope of the curve;
%       stat.PeriodFreq is the frequency (in Hz) of the main periodicity;
%       stat.PeriodAmp is the normalized amplitude of the main periodicity;
%       stat.PeriodEntropy is the entropy of the periodicity curve.
%   The main periodicity and periodicity curve are evaluated through the
%       computation of the autocorrelation sequence related to f.
%
%   f can be itself a structure array composed of features. In this case,
%       stat will be structured the same way.
%
% mirstat does not work for multi-channels objects.

if isa(f,'mirstruct')
    varargout = {set(f,'Stat',1)};
elseif isstruct(f)
    if isdesign(f)
        f.Stat = 1;
        varargout = {f};
    else
        fields = fieldnames(f);
        for i = 1:length(fields)
            field = fields{i};
            ff = f.(field);
            if iscell(ff) && isa(ff{1},'mirdata')
                ff = ff{1};
            end
            if isa(ff,'mirdata')
                if i == 1 
                    la = get(ff,'Label');
                    if not(isempty(la) || isempty(la{1}))
                        stat.Class = la;
                    end
                end
                ff = set(ff,'Label','');
            end
            stat.(field) = mirstat(ff,'FileNames',0);
        end
        if isempty(varargin)
            f0 = f;
            while isstruct(f0)
                fields = fieldnames(f0);
                f0 = f0.(fields{1});
            end
            if iscell(f0)
                f0 = f0{1};
            end
            stat.FileNames = get(f0,'Name');
        end
        varargout = {stat};
    end
elseif iscell(f)
    if 0 %ischar(f{1})
        varargout = {f};
    else
        res = zeros(length(f),1);
        for i = 1:length(f)
            res(i) = mirstat(f{i});
        end
        varargout = {res};
    end
elseif isnumeric(f)
    f(isnan(f)) = [];
    varargout = {mean(f)};
else
            alongfiles.key = 'AlongFiles';
            alongfiles.type = 'Boolean';
            alongfiles.default = 0;
        option.alongfiles = alongfiles;

            filenames.key = 'FileNames';
            filenames.type = 'Boolean';
            filenames.default = 1;
        option.filenames = filenames;
        
    specif.option = option;

    specif.nochunk = 1;
    varargout = mirfunction(@mirstat,f,varargin,nargout,specif,@init,@main);
end


function [x type] = init(x,option)
type = '';


function stat = main(f,option,postoption)
if iscell(f)
    f = f{1};
end
if isa(f,'mirhisto')
    warning('WARNING IN MIRSTAT: histograms are not taken into consideration yet.')
    stat = struct;
    return
end
fp = get(f,'FramePos');
if haspeaks(f)
    ppp = get(f,'PeakPrecisePos');
    if not(isempty(ppp)) && not(isempty(ppp{1}))
        stat = addstat(struct,ppp,fp,'PeakPos');
        stat = addstat(stat,get(f,'PeakPreciseVal'),fp,'PeakMag');
    else
        if isa(f,'mirkeystrength') || (isa(f,'mirchromagram') && get(f,'Wrap'))
            stat = struct; % This needs to be defined using some kind of circular statistics..
        else
            stat = addstat(struct,get(f,'PeakPosUnit'),fp,'PeakPos');
        end
        stat = addstat(stat,get(f,'PeakVal'),fp,'PeakMag');
    end
else
    stat = addstat(struct,get(f,'Data'),fp,'',option.alongfiles,...
                          get(f,'Name'),get(f,'Label'));
end
if option.filenames
    stat.FileNames = get(f,'Name');
end


function stat = addstat(stat,d,fp,field,alongfiles,filename,labels)
l = length(d);
if nargin<5
    alongfiles = 0;
end
if nargin<7
    labels = {};
end
if not(alongfiles) || l == 1
    anyframe = 0;
    for i = 1:l
        if not(iscell(d{i}))
            d{i} = {d{i}};
        end
        for k = 1:length(d{i})
            dd = d{i}{k};
            if iscell(dd)
                if length(dd)>1
                    anyframe = 1;
                end
                dn = cell2array(dd);
                [m{i}{k},s{i}{k},sl{i}{k},pa{i}{k},pf{i}{k},pe{i}{k}] ...
                    = computestat(dn,fp{i}{k});
            elseif size(dd,2) < 2
                nonan = find(not(isnan(dd)));
                dn = dd(nonan);
                if isempty(dn)
                    m{i}{k} = NaN;
                else
                    m{i}{k} = mean(dn,2);
                end
                s{i}{k} = NaN;
                sl{i}{k} = NaN;
                pa{i}{k} = NaN;
                pf{i}{k} = NaN;
                pe{i}{k} = NaN;
            else
                anyframe = 1;
                s1 = size(dd,1);
                s3 = size(dd,3);
                dd = mean(dd,4); %mean(dd,3),4);
                m{i}{k} = NaN(s1,1,s3);
                s{i}{k} = NaN(s1,1,s3);
                sl{i}{k} = NaN(s1,1,s3);
                pa{i}{k} = NaN(s1,1,s3);
                pf{i}{k} = NaN(s1,1,s3);
                pe{i}{k} = NaN(s1,1,s3);
                for h = 1:s3
                    for j = 1:s1
                        [m{i}{k}(j,1,h),s{i}{k}(j,1,h),sl{i}{k}(j,1,h),...
                         pa{i}{k}(j,1,h),pf{i}{k}(j,1,h),pe{i}{k}(j,1,h)] = ...
                            computestat(dd(j,:,h),fp{i}{k});
                    end
                end
            end
        end
    end
    if anyframe
        fields = {'Mean','Std','Slope','PeriodFreq','PeriodAmp','PeriodEntropy'};
        stats = {m,s,sl,pf,pa,pe};   
    else
        fields = {'Mean'};
        stats = {m};   
    end
    for i = 1:length(stats)
        data = stats{i};
        data = uncell(data,NaN);
        stat.(strcat(field,fields{i})) = data;
    end
else
    if iscell(d{1}{1})
        slash = strfind(filename{1},'/');
        nbfolders = 1;
        infolder = 0;
        foldername{1} = filename{1}(1:slash(end)-1);
        for i = 1:length(d)
            slash = strfind(filename{i},'/');
            if not(strcmpi(filename{i}(1:slash(end)-1),foldername))
                nbfolders = nbfolders + 1;
                infolder = 0;
                foldername{nbfolders} = filename{i}(1:slash(end)-1);
            end
            infolder = infolder+1;
            dd{nbfolders}(infolder,:) = cell2array(d{i}{1});
        end
        for i = 1:length(dd)
            figure
            plot(dd{i}')
            stat.Mean{i} = mean(dd{i});
            stat.Std{i} = std(dd{i});
        end
    end
end
if not(isempty(labels) || isempty(labels{1}))
    stat.Class = labels;
end


function dn = cell2array(dd)
dn = zeros(1,length(dd));
for j = 1:length(dd)
    if isempty(dd{j})
        dn(j) = NaN;
    else
        dn(j) = dd{j}(1);
    end
end


function [m,s,sl,pa,pf,pe] = computestat(d,fp)
m = NaN;
s = NaN;
sl = NaN;
pa = NaN;
pf = NaN;
pe = NaN;
diffp = fp(1,2:end) - fp(1,1:end-1);
if isempty(diffp) || sum(round((diffp(2:end)-diffp(1:end-1))*1000))
    % Not regular sampling (in mirattacktime for instance)
    framesampling = NaN;
else
    framesampling = fp(1,2)-fp(1,1);
end
nonan = find(not(isnan(d)));
if not(isempty(nonan))
    dn = d(nonan);
    m = mean(dn,2);
    s = std(dn,0,2);
    if not(isnan(s))
        if s
            dk = (dn-m)/s;
            tk = linspace(0,1,size(d,2));
            sl = dk(:)'/tk(nonan);
        elseif size(s,2) == 1
            s = NaN;
        end
    end
    if length(dn)>1
        cor = xcorr(dn',dn','coeff');
        cor = cor(ceil(length(cor)/2):end);
        % let's zero the first descending slope of the
        % autocorrelation function
        firstmin = find(cor(2:end)>cor(1:end-1));
        if not(isempty(firstmin) || isnan(framesampling))
            cor2 = cor;
            cor2(1:firstmin(1)) = 0;
            [pa,pfk] = max(cor2);
            if pfk > 1
                pf = 1/(pfk-1)/framesampling;
            end
        end
        cor = abs(cor);
        cor = cor/sum(cor);
        pe = -sum(cor.*log(cor+1e-12))./log(length(cor));
    end
end


function b = isdesign(f)
if iscell(f)
    f = f{1};
end
if isa(f,'mirdesign') || isa(f,'mirstruct')
    b = 1;
elseif isa(f,'mirdata') || not(isstruct(f))
    b = 0;
else
    fields = fieldnames(f);
    b = isdesign(f.(fields{1}));
end

Contact us at files@mathworks.com