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

mirnovelty(orig,varargin)
function varargout = mirnovelty(orig,varargin)
%   n = mirnovelty(m) evaluates the novelty score from a similarity matrix.
%   [n,m] = mirnovelty(m) also return the similarity matrix.
%   Optional argument: 
%       mirnovelty(...,'Distance',f) specifies the name of a dissimilarity
%           distance function, from those proposed in the Statistics Toolbox
%               (help pdist).
%           default value: f = 'cosine'
%       mirnovelty(...,'Similarity',f) specifies the name of a similarity
%           measure function. This function is applied to the result of the
%           distance function. cf. mirsimatrix 
%           default value: f = 'exponential'
%               corresponding to f(x) = exp(-x)
%       mirnovelty(...,'KernelSize',s) or more simply mirnovelty(...,s) 
%           specifies the length of the gaussian kernel, in samples.
%           default value: s = 64.
%       mirnovelty(...,'Normal',0) does not normalize the novelty curve
%           between the values 0 and 1.
%       mirnovelty(...,'Horizontal') uses the 'Horizontal' option in
%           mirsimatrix instead of 'TimeLag' used here by default.
%
%   Foote, J. & Cooper, M. (2003). Media Segmentation using Self-Similarity
% Decomposition,. In Proc. SPIE Storage and Retrieval for Multimedia
% Databases, Vol. 5021, pp. 167-75.

        dist.key = 'Distance';
        dist.type = 'String';
        dist.default = 'cosine';
    option.dist = dist;

        sm.key = {'Measure','Similarity'};
        sm.type = 'String';
        sm.default = 'exponential';
    option.sm = sm;

        K.key = {'KernelSize','Width'};
        K.type = 'Integer';
        K.default = 64;
    option.K = K;
    
        transf.type = 'String';
        transf.default = 'TimeLag';
        transf.choice = {'Horizontal','TimeLag'};
    option.transf = transf;

        normal.key = 'Normal';
        normal.type = 'Boolean';
        normal.default = 1;
        normal.when = 'After';
    option.normal = normal;
    
specif.option = option;
specif.nochunk = 1;
varargout = mirfunction(@mirnovelty,orig,varargin,nargout,specif,@init,@main);
    

function [x type] = init(x,option)
type = 'mirscalar';
if not(isamir(x,'mirscalar') && strcmp(get(x,'Title'),'Novelty'))
    x = mirsimatrix(x,'Distance',option.dist,'Similarity',option.sm,...
                      'Width',option.K,option.transf);
end
if isa(x,'mirdesign')
    x = set(x,'Overlap',ceil(option.K));
end


function y = main(orig,option,postoption)
if iscell(orig)
    orig = orig{1};
end
if not(isa(orig,'mirscalar'))
    s = get(orig,'Data');
    dw = get(orig,'DiagWidth');
    for k = 1:length(s)
        if isnumeric(dw)
            dwk = dw;
        else
            dwk = dw{k};
        end
        if option.K
            cgs = min(option.K,dwk);
        else
            cgs = dwk;
        end
        cg = checkergauss(cgs,option.transf);
        disp('Computing convolution, please wait...')
        for z = 1:length(s{k})
            sz = s{k}{z};
            szma = max(max(sz));
            szmi = min(min(sz));
            sz = (sz-szmi)/(szma-szmi);
            sz = 2*sz-1;
            sz(isnan(sz)) = 0;
            cv = convolve2(sz,cg,'same');
            nl = size(cv,1);
            nc = size(cv,2);
            if nl == 0
                warning('WARNING IN NOVELTY: No frame decomposition. The novelty score cannot be computed.');
                score{k}{z} = [];
            else
                sco = cv(floor(size(cv,1)/2),:);
                incr = find(diff(sco)>=0);
                if not(isempty(incr))
                    decr = find(diff(sco)<=0);
                    sco(1:incr(1)-1) = NaN(1,incr(1)-1);
                    if not(isempty(decr))
                        sco(decr(end)+1:end) = NaN(1,length(sco)-decr(end));
                    end
                    incr = find(diff(sco)>=0);
                    sco2 = sco;
                    if not(isempty(incr))
                        sco2 = sco2(1:incr(end)+1);
                    end
                    decr = find(diff(sco)<=0);
                    if not(isempty(decr)) && decr(1)>2
                        sco2 = sco2(decr(1)-1:end);
                    end
                    mins = min(sco2);
                    rang = find(sco>= mins);
                    if not(isempty(rang))
                        sco(1:rang(1)-1) = NaN(1,rang(1)-1);
                        sco(rang(end)+1:end) = NaN(1,length(sco)-rang(end));
                    end
                end
                score{k}{z} = sco;
            end
        end
    end
else
    score = get(orig,'Data');
end
if not(isempty(postoption)) && postoption.normal
    for k = 1:length(score)
        for l = 1:length(score{k})
            sco = score{k}{l};
            sco = (sco-min(sco))/(max(sco)-min(sco));
            score{k}{l} = sco;
        end
    end
end
n = mirscalar(orig,'Data',score,'Title','Novelty'); 
y = {n orig};


function y = checkergauss(N,transf)
hN = ceil(N/2);
if strcmpi(transf,'TimeLag')
    y = zeros(2*N,N);
    for j = 1:N
        for i = 1:2*N+1
            g = exp(-((((i-N)-(j-hN))/hN)^2 + (((j-hN)/hN)^2))*4);
            if xor(j>hN,j-hN>i-N)
                y(i,j) = -g;
            elseif j>hN+i || j-hN<i-2*N
                y(i,j) = 0;
            else
                y(i,j) = g;
            end
        end
    end
else
    y = zeros(N);
    for i = 1:N
        for j = 1:N
            g = exp(-(((i-hN)/hN)^2 + (((j-hN)/hN)^2))*4);
            if xor(j-hN>floor((i-hN)/2),j-hN>floor((hN-i)/2))
                y(i,j) = -g;
            else
                y(i,j) = g;
            end
        end
    end
end

Contact us at files@mathworks.com