diff toolboxes/MIRtoolbox1.3.2/MIRToolbox/mirflux.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/mirflux.m	Tue Feb 10 15:05:51 2015 +0000
@@ -0,0 +1,254 @@
+function varargout = mirflux(orig,varargin)
+%   f = mirflux(x) measures distance between successive frames.
+%   First argument:
+%       If x is a spectrum, this corresponds to spectral flux.
+%       But the flux of any other data can be computed as well.
+%       If x is an audio file or audio signal, the spectral flux is
+%           computed by default.
+%   Optional arguments:
+%       f = mirflux(x,'Frame',...) specifies the frame parameters, if x is
+%           not already decomposed into frames. Default values are frame 
+%           length of .2 seconds and hop factor of 1.3.
+%       f = mirflux(x,'Dist',d) specifies the distance between 
+%           successive  frames:                 (IF 'COMPLEX': DISTANCE = 'CITY' ALWAYS)
+%           d = 'Euclidian': Euclidian distance (Default)
+%           d = 'City': City-block distance
+%           d = 'Cosine': Cosine distance (or normalized correlation)
+%       f = mirflux(...,'Inc'): Only positive difference between frames are
+%           summed, in order to focus on increase of energy solely.
+%       f = mirflux(...,'Complex'), for spectral flux, combines use of
+%           energy and phase information (Bello et al, 2004).
+%       f = mirflux(...,'Halfwave'): performs a half-wave  rectification on
+%           the result.
+%       f = mirflux(...,'Median',l,C): removes small spurious peaks by
+%           subtracting to the result its median filtering. The median
+%           filter computes the point-wise median inside a window of length
+%           l (in seconds), that  includes a same number of previous and
+%           next samples. C is a scaling factor whose purpose is to
+%           artificially rise the curve slightly above the steady state of
+%           the signal. If no parameters are given, the default values are:
+%           l = 0.2 s. and C = 1.3
+%       f = mirflux(...,'Median',l,C,'Halfwave'): The scaled median
+%           filtering is designed to be succeeded by the  half-wave 
+%           rectification process in order to select peaks above the
+%           dynamic threshold calculated with the help of the median
+%           filter. The resulting signal is called "detection function"
+%           (Alonso, David, Richard, 2004). To ensure accurate detection,
+%           the length l of the median filter must be longer than the
+%           average width of the peaks of the detection function.
+%
+%   (Bello et al, 2004) Juan P. Bello, Chris Duxbury, Mike Davies, and Mark
+%   Sandler, On the Use of Phase and Energy for Musical Onset Detection in
+%   the Complex Domain, IEEE SIGNAL PROCESSING LETTERS, VOL. 11, NO. 6,
+%   JUNE 2004
+
+        dist.key = 'Dist';
+        dist.type = 'String';
+        dist.choice = {'Euclidian','City','Cosine'};  %PDIST???? (euclidean)
+        dist.default = 'Euclidian';
+    option.dist = dist;
+    
+        inc.key = 'Inc';
+        inc.type = 'Boolean';
+        inc.default = 0;
+    option.inc = inc;
+    
+        complex.key = 'Complex';
+        complex.type = 'Boolean';
+        complex.default = 0;
+    option.complex = complex;
+    
+        h.key = 'Halfwave';
+        h.type = 'Boolean';
+        h.default = 0;
+        h.when = 'After';
+    option.h = h;
+    
+        median.key = 'Median';
+        median.type = 'Integer';
+        median.number = 2;
+        median.default = [0 0];
+        median.keydefault = [.2 1.3];
+        median.when = 'After';
+    option.median = median;
+    
+        frame.key = 'Frame';
+        frame.type = 'Integer';
+        frame.number = 2;
+        frame.default = [.05 .5];
+    option.frame = frame;
+    
+specif.option = option;
+     
+varargout = mirfunction(@mirflux,orig,varargin,nargout,specif,@init,@main);
+
+
+function [x type] = init(x,option)
+if isamir(x,'miraudio') 
+    if isframed(x)
+        x = mirspectrum(x);
+    else
+        x = mirspectrum(x,'Frame',option.frame.length.val,option.frame.length.unit,...
+                                  option.frame.hop.val,option.frame.hop.unit);
+    end
+end
+if isa(x,'mirdesign')
+    x = set(x,'Overlap',1);
+end
+type = 'mirscalar';
+
+
+function f = main(s,option,postoption)
+if iscell(s)
+    s = s{1};
+end
+t = get(s,'Title');
+if isa(s,'mirscalar') && ...
+        (strcmp(t,'Harmonic Change Detection Function') || ...
+         (length(t)>4 && strcmp(t(end-3:end),'flux')) || ...
+         (length(t)>5 && strcmp(t(end-4:end-1),'flux')))
+    if not(isempty(postoption))
+        f = modif(s,postoption);
+    end
+else
+    if isa(s,'mirspectrum')
+        t = 'Spectral';
+    end
+    m = get(s,'Data'); 
+    if option.complex
+        if not(isa(s,'mirspectrum'))
+            error('ERROR IN MIRFLUX: ''Complex'' option only defined for spectral flux.');
+        end
+        ph = get(s,'Phase');
+    end
+    param.complex = option.complex;
+    param.inc = option.inc;
+    fp = get(s,'FramePos');
+    if strcmp(t,'Tonal centroid')
+        t = 'Harmonic Change Detection Function';
+    else
+        t = [t,' flux'];
+    end
+    disp(['Computing ' t '...'])
+    ff = cell(1,length(m));
+    newsr = cell(1,length(m));
+    dist = str2func(option.dist);
+    %[tmp s] = gettmp(s); %get(s,'Tmp');
+    for h = 1:length(m)
+        ff{h} = cell(1,length(m{h}));
+        if not(iscell(m{h}))
+            m{h} = {m{h}};
+        end
+        for i = 1:length(m{h})
+            mi = m{h}{i};
+            if size(mi,3) > 1 && size(mi,1) == 1
+                mi = reshape(mi,size(mi,2),size(mi,3))';
+            end
+            if option.complex
+                phi = ph{h}{i};
+            end
+            fpi = fp{h}{i};
+            %if 0 %not(isempty(tmp)) && isstruct(tmp) && isfield(tmp,'mi')
+            %    mi = [tmp.mi mi];
+            %    fpi = [tmp.fpi fpi];
+            %end
+            nc = size(mi,2);
+            np = size(mi,3);
+            if nc == 1
+                warning('WARNING IN MIRFLUX: Flux can only be computed on signal decomposed into frames.');
+                ff{h}{i} = NaN(1,1,np);
+            else
+                if option.complex
+                    fl = zeros(1,nc-2,np);
+                    for k = 1:np
+                        d = diff(phi(:,:,k),2,2);
+                        d = d/(2*pi) - round(d/(2*pi));
+                        g = sqrt(mi(:,3:end,k).^2 + mi(:,2:(end-1),k).^2 ...
+                                                  - 2.*mi(:,3:end,k)...
+                                                     .*mi(:,2:(end-1),k)...
+                                                     .*cos(d));
+                        fl(1,:,k) = sum(g);
+                    end
+                    fp{h}{i} = fpi(:,3:end);
+                else
+                    fl = zeros(1,nc-1,np);
+                    for k = 1:np
+                        for j = 1:nc-1
+                            fl(1,j,k) = dist(mi(:,j,k),mi(:,j+1,k),option.inc);
+                        end
+                    end
+                    fp{h}{i} = fpi(:,2:end);
+                end
+                ff{h}{i} = fl;
+                %tmp.mi = mi(:,end,:);
+                %tmp.fpi = fpi(:,end,:);
+            end
+        end
+        %tmp = [];
+        if size(fpi,2)<2
+            newsr{h} = 0;
+        else
+            newsr{h} = 1/(fpi(1,2)-fpi(1,1));
+        end
+    end
+    f = mirscalar(s,'Data',ff,'FramePos',fp,'Sampling',newsr,...
+                        'Title',t,'Parameter',param); %,'Tmp',tmp);
+    %f = settmp(f,tmp);
+    if not(isempty(postoption))
+        f = modif(f,postoption);
+    end
+end
+
+
+function f = modif(f,option)
+fl = get(f,'Data'); 
+r = get(f,'Sampling');
+for h = 1:length(fl)
+    for i = 1:length(fl{h})
+        fli = fl{h}{i};
+        nc = size(fli,2);
+        np = size(fli,3);
+        if option.median(1)
+            ffi = zeros(1,nc,np);
+            lr = round(option.median(1)*r{i});
+            for k = 1:np
+                for j = 1:nc
+                    ffi(:,j,k) = fli(:,j,k) - ...
+                        option.median(2) * median(fli(:,max(1,j-lr):min(nc-1,j+lr),k));
+                end
+            end
+            fli = ffi;
+        end
+        if option.h
+            fli = hwr(fli);
+        end
+        fl{h}{i} = fli;
+    end
+end
+f = set(f,'Data',fl);
+
+
+function y = Euclidian(mi,mj,inc)
+if inc
+    y = sqrt(sum(max(0,(mj-mi)).^2));
+else
+    y = sqrt(sum((mj-mi).^2));
+end
+
+
+function y = City(mi,mj,inc)
+if inc
+    y = sum(max(0,(mj-mi)));
+else
+    y = sum(abs(mj-mi));
+end
+
+
+function d = Cosine(r,s,inc)
+nr = sqrt(r'*r);
+ns = sqrt(s'*s);
+if or(nr == 0, ns == 0);
+    d = 1;
+else
+    d = 1 - r'*s/nr/ns;
+end
\ No newline at end of file