annotate toolboxes/MIRtoolbox1.3.2/MIRToolbox/@mirchromagram/mirchromagram.m @ 0:e9a9cd732c1e tip

first hg version after svn
author wolffd
date Tue, 10 Feb 2015 15:05:51 +0000
parents
children
rev   line source
wolffd@0 1 function varargout = mirchromagram(orig,varargin)
wolffd@0 2 % c = mirchromagram(x) computes the chromagram, or distribution of energy
wolffd@0 3 % along pitches, of the audio signal x.
wolffd@0 4 % (x can be the name of an audio file as well, or a spectrum, ...)
wolffd@0 5 % Optional argument:
wolffd@0 6 % c = mirchromagram(...,'Tuning',t): specifies the central frequency
wolffd@0 7 % (in Hz.) associated to chroma C.
wolffd@0 8 % Default value, t = 261.6256 Hz
wolffd@0 9 % c = mirchromagram(...,'Wrap',w): specifies whether the chromagram is
wolffd@0 10 % wrapped or not.
wolffd@0 11 % w = 1: groups all the pitches belonging to same pitch classes
wolffd@0 12 % (default value)
wolffd@0 13 % w = 0: pitches are considered as absolute values.
wolffd@0 14 % c = mirchromagram(...,'Frame',l,h) orders a frame decomposition of window
wolffd@0 15 % length l (in seconds) and hop factor h, expressed relatively to
wolffd@0 16 % the window length. For instance h = 1 indicates no overlap.
wolffd@0 17 % Default values: l = .2 seconds and h = .05
wolffd@0 18 % c = mirchromagram(...,'Center'): centers the result.
wolffd@0 19 % c = mirchromagram(...,'Normal',n): performs a n-norm of the
wolffd@0 20 % resulting chromagram. Toggled off if n = 0
wolffd@0 21 % Default value: n = Inf (corresponding to a normalization by
wolffd@0 22 % the maximum value).
wolffd@0 23 % c = mirchromagram(...,'Pitch',p): specifies how to label chromas in
wolffd@0 24 % the figures.
wolffd@0 25 % p = 1: chromas are labeled using pitch names (default)
wolffd@0 26 % alternative syntax: chromagram(...,'Pitch')
wolffd@0 27 % p = 0: chromas are labeled using MIDI pitch numbers
wolffd@0 28 % c = mirchromagram(...,'Triangle'): weight the contribution of each
wolffd@0 29 % frequency with respect to the distance with the actual
wolffd@0 30 % frequency of the corresponding chroma.
wolffd@0 31 % c = mirchromagram(...,'Weight',o): specifies the relative radius of
wolffd@0 32 % the weighting window, with respect to the distance between
wolffd@0 33 % frequencies of successive chromas.
wolffd@0 34 % o = 1: each window begins at the centers of the previous one.
wolffd@0 35 % o = .5: each window begins at the end of the previous one.
wolffd@0 36 % (default value)
wolffd@0 37 % mirchromagram(...,'Min',mi) indicates the lowest frequency taken into
wolffd@0 38 % consideration in the spectrum computation, expressed in Hz.
wolffd@0 39 % Default value: 100 Hz. (Gomez, 2006)
wolffd@0 40 % mirchromagram(...,'Max',ma) indicates the highest frequency taken into
wolffd@0 41 % consideration in the spectrum computation, expressed in Hz.
wolffd@0 42 % This upper limit is further shifted to a highest value until
wolffd@0 43 % the frequency range covers an exact multiple of octaves.
wolffd@0 44 % Default value: 5000 Hz. (Gomez, 2006)
wolffd@0 45 % mirchromagram(...,'Res',r) indicates the resolution of the
wolffd@0 46 % chromagram in number of bins per octave.
wolffd@0 47 % Default value, r = 12.
wolffd@0 48 %
wolffd@0 49 % Gómez, E. (2006). Tonal description of music audio signal. Phd thesis,
wolffd@0 50 % Universitat Pompeu Fabra, Barcelona .
wolffd@0 51
wolffd@0 52 cen.key = 'Center';
wolffd@0 53 cen.type = 'Boolean';
wolffd@0 54 cen.default = 0;
wolffd@0 55 option.cen = cen;
wolffd@0 56
wolffd@0 57 nor.key = {'Normal','Norm'};
wolffd@0 58 nor.type = 'Integer';
wolffd@0 59 nor.default = Inf;
wolffd@0 60 option.nor = nor;
wolffd@0 61
wolffd@0 62 wth.key = 'Weight';
wolffd@0 63 wth.type = 'Integer';
wolffd@0 64 wth.default = .5;
wolffd@0 65 option.wth = wth;
wolffd@0 66
wolffd@0 67 tri.key = 'Triangle';
wolffd@0 68 tri.type = 'Boolean';
wolffd@0 69 tri.default = 0;
wolffd@0 70 option.tri = tri;
wolffd@0 71
wolffd@0 72 wrp.key = 'Wrap';
wolffd@0 73 wrp.type = 'Boolean';
wolffd@0 74 wrp.default = 1;
wolffd@0 75 option.wrp = wrp;
wolffd@0 76
wolffd@0 77 plabel.key = 'Pitch';
wolffd@0 78 plabel.type = 'Boolean';
wolffd@0 79 plabel.default = 1;
wolffd@0 80 option.plabel = plabel;
wolffd@0 81
wolffd@0 82 thr.key = {'Threshold','dB'};
wolffd@0 83 thr.type = 'Integer';
wolffd@0 84 thr.default = 20;
wolffd@0 85 option.thr = thr;
wolffd@0 86
wolffd@0 87 min.key = 'Min';
wolffd@0 88 min.type = 'Integer';
wolffd@0 89 min.default = 100;
wolffd@0 90 option.min = min;
wolffd@0 91
wolffd@0 92 max.key = 'Max';
wolffd@0 93 max.type = 'Integer';
wolffd@0 94 max.default = 5000;
wolffd@0 95 option.max = max;
wolffd@0 96
wolffd@0 97 res.key = 'Res';
wolffd@0 98 res.type = 'Integer';
wolffd@0 99 res.default = 12;
wolffd@0 100 option.res = res;
wolffd@0 101
wolffd@0 102 origin.key = 'Tuning';
wolffd@0 103 origin.type = 'Integer';
wolffd@0 104 origin.default = 261.6256;
wolffd@0 105 option.origin = origin;
wolffd@0 106
wolffd@0 107 specif.option = option;
wolffd@0 108 specif.defaultframelength = .2;
wolffd@0 109 specif.defaultframehop = .05;
wolffd@0 110
wolffd@0 111 varargout = mirfunction(@mirchromagram,orig,varargin,nargout,specif,@init,@main);
wolffd@0 112
wolffd@0 113
wolffd@0 114 function [x type] = init(x,option)
wolffd@0 115 if isamir(x,'mirtemporal') || isamir(x,'mirspectrum')
wolffd@0 116 freqmin = option.min;
wolffd@0 117 freqmax = freqmin*2;
wolffd@0 118 while freqmax < option.max
wolffd@0 119 freqmax = freqmax*2;
wolffd@0 120 end
wolffd@0 121 %freqres = freqmin*(2.^(1/option.res)-1);
wolffd@0 122 % Minimal frequency resolution should correspond to frequency range
wolffd@0 123 % between the first two bins of the chromagram
wolffd@0 124
wolffd@0 125 x = mirspectrum(x,'dB',option.thr,'Min',freqmin,'Max',freqmax,...
wolffd@0 126 'NormalInput','MinRes',option.res,'OctaveRatio',.85);
wolffd@0 127 %freqres*.5,...
wolffd@0 128 % 'WarningRes',freqres);
wolffd@0 129 end
wolffd@0 130 type = 'mirchromagram';
wolffd@0 131
wolffd@0 132
wolffd@0 133 function c = main(orig,option,postoption)
wolffd@0 134 if iscell(orig)
wolffd@0 135 orig = orig{1};
wolffd@0 136 end
wolffd@0 137 if option.res == 12
wolffd@0 138 chromascale = {'C','C#','D','D#','E','F','F#','G','G#','A','A#','B'};
wolffd@0 139 else
wolffd@0 140 chromascale = 1:option.res;
wolffd@0 141 option.plabel = 0;
wolffd@0 142 end
wolffd@0 143 if isa(orig,'mirchromagram')
wolffd@0 144 c = modif(orig,option,chromascale);
wolffd@0 145 else
wolffd@0 146 c.plabel = 1;
wolffd@0 147 c.wrap = 0;
wolffd@0 148 c.chromaclass = {};
wolffd@0 149 c.chromafreq = {};
wolffd@0 150 c.register = {};
wolffd@0 151 c = class(c,'mirchromagram',mirdata(orig));
wolffd@0 152 c = purgedata(c);
wolffd@0 153 c = set(c,'Title','Chromagram','Ord','magnitude','Interpolable',0);
wolffd@0 154 if option.wrp
wolffd@0 155 c = set(c,'Abs','chroma class');
wolffd@0 156 else
wolffd@0 157 c = set(c,'Abs','chroma');
wolffd@0 158 end
wolffd@0 159 m = get(orig,'Magnitude');
wolffd@0 160 f = get(orig,'Frequency');
wolffd@0 161 %disp('Computing chromagram...')
wolffd@0 162 fs = get(orig,'Sampling');
wolffd@0 163 n = cell(1,length(m)); % The final structured list of magnitudes.
wolffd@0 164 cc = cell(1,length(m)); % The final structured list of chroma classes.
wolffd@0 165 o = cell(1,length(m)); % The final structured list of octave registers.
wolffd@0 166 p = cell(1,length(m)); % The final structured list of chromas.
wolffd@0 167 cf = cell(1,length(m)); % The final structured list of central frequencies related to chromas.
wolffd@0 168 for i = 1:length(m)
wolffd@0 169 mi = m{i};
wolffd@0 170 fi = f{i};
wolffd@0 171 if not(iscell(mi))
wolffd@0 172 mi = {mi};
wolffd@0 173 fi = {fi};
wolffd@0 174 end
wolffd@0 175 ni = cell(1,length(mi)); % The list of magnitudes.
wolffd@0 176 ci = cell(1,length(mi)); % The list of chroma classes.
wolffd@0 177 oi = cell(1,length(mi)); % The list of octave registers.
wolffd@0 178 pi = cell(1,length(mi)); % The list of absolute chromas.
wolffd@0 179 cfi = cell(1,length(mi)); % The central frequency of each chroma.
wolffd@0 180 for j = 1:length(mi)
wolffd@0 181 mj = mi{j};
wolffd@0 182 fj = fi{j};
wolffd@0 183
wolffd@0 184 % Let's remove the frequencies exceeding the last whole octave.
wolffd@0 185 minfj = min(min(min(fj)));
wolffd@0 186 maxfj = max(max(max(fj)));
wolffd@0 187 maxfj = minfj*2^(floor(log2(maxfj/minfj)));
wolffd@0 188 fz = find(fj(:,1,1,1) > maxfj);
wolffd@0 189 mj(fz,:,:,:) = [];
wolffd@0 190 fj(fz,:,:,:) = [];
wolffd@0 191
wolffd@0 192 [s1 s2 s3] = size(mj);
wolffd@0 193
wolffd@0 194 cj = freq2chro(fj,option.res,option.origin);
wolffd@0 195 if not(ismember(min(cj)+1,cj))
wolffd@0 196 warning('WARNING IN MIRCHROMAGRAM: Frequency resolution of the spectrum is too low.');
wolffd@0 197 display('The conversion of low frequencies into chromas may be incorrect.');
wolffd@0 198 end
wolffd@0 199 ccj = min(min(min(cj))):max(max(max(cj)));
wolffd@0 200 sc = length(ccj); % The size of range of absolute chromas.
wolffd@0 201 mat = zeros(s1,sc);
wolffd@0 202 fc = chro2freq(ccj,option.res,option.origin); % The absolute chromas in Hz.
wolffd@0 203 fl = chro2freq(ccj-1,option.res,option.origin); % Each previous chromas in Hz.
wolffd@0 204 fr = chro2freq(ccj+1,option.res,option.origin); % Each related next chromas in Hz.
wolffd@0 205 for k = 1:sc
wolffd@0 206 rad = find(and(fj(:,1) > fc(k)-option.wth*(fc(k)-fl(k)),...
wolffd@0 207 fj(:,1) < fc(k)-option.wth*(fc(k)-fr(k))));
wolffd@0 208 if option.tri
wolffd@0 209 dist = fc(k) - fj(:,1,1,1);
wolffd@0 210 rad1 = dist/(fc(k) - fl(k))/option.wth;
wolffd@0 211 rad2 = dist/(fc(k) - fr(k))/option.wth;
wolffd@0 212 ndist = max(rad1,rad2);
wolffd@0 213 mat(:,k) = max(min(1-ndist,1),0)/length(rad);
wolffd@0 214 else
wolffd@0 215 mat(rad,k) = ones(length(rad),1)/length(rad);
wolffd@0 216 end
wolffd@0 217 if k ==1 || k == sc
wolffd@0 218 mat(:,k) = mat(:,k)/2;
wolffd@0 219 end
wolffd@0 220 end
wolffd@0 221 nj = zeros(sc,s2,s3);
wolffd@0 222 for k = 1:s2
wolffd@0 223 for l = 1:s3
wolffd@0 224 nj(:,k,l) = (mj(:,k,l)'*mat)';
wolffd@0 225 end
wolffd@0 226 end
wolffd@0 227 cj = mod(ccj',option.res);
wolffd@0 228 oi{j} = floor(ccj/option.res)+4;
wolffd@0 229 if option.plabel
wolffd@0 230 pj = strcat(chromascale(cj+1)',num2str(oi{j}'));
wolffd@0 231 else
wolffd@0 232 pj = ccj'+60;
wolffd@0 233 end
wolffd@0 234 ci{j} = repmat(cj,[1,s2,s3]);
wolffd@0 235 pi{j} = repmat(pj,[1,s2,s3]);
wolffd@0 236 ni{j} = nj;
wolffd@0 237 cfi{j} = fc;
wolffd@0 238 end
wolffd@0 239 n{i} = ni;
wolffd@0 240 cc{i} = ci;
wolffd@0 241 o{i} = oi;
wolffd@0 242 p{i} = pi;
wolffd@0 243 cf{i} = cfi;
wolffd@0 244 end
wolffd@0 245 c = set(c,'Magnitude',n,'Chroma',p,'ChromaClass',cc,...
wolffd@0 246 'ChromaFreq',cf,'Register',o);
wolffd@0 247 c = modif(c,option,chromascale);
wolffd@0 248 c = {c orig};
wolffd@0 249 end
wolffd@0 250
wolffd@0 251
wolffd@0 252 function c = modif(c,option,chromascale)
wolffd@0 253 if option.plabel
wolffd@0 254 c = set(c,'PitchLabel',1);
wolffd@0 255 end
wolffd@0 256 if option.cen || option.nor || option.wrp
wolffd@0 257 n = get(c,'Magnitude');
wolffd@0 258 p = get(c,'Chroma');
wolffd@0 259 cl = get(c,'ChromaClass');
wolffd@0 260 fp = get(c,'FramePos');
wolffd@0 261 n2 = cell(1,length(n));
wolffd@0 262 p2 = cell(1,length(n));
wolffd@0 263 wrp = option.wrp && not(get(c,'Wrap'));
wolffd@0 264 for i = 1:length(n)
wolffd@0 265 ni = n{i};
wolffd@0 266 pi = p{i};
wolffd@0 267 cli = cl{i};
wolffd@0 268 if not(iscell(ni))
wolffd@0 269 ni = {ni};
wolffd@0 270 pi = {pi};
wolffd@0 271 cli = {cli};
wolffd@0 272 end
wolffd@0 273 if wrp
wolffd@0 274 c = set(c,'Wrap',option.wrp);
wolffd@0 275 end
wolffd@0 276 n2i = cell(1,length(ni));
wolffd@0 277 p2i = cell(1,length(ni));
wolffd@0 278 for j = 1:length(ni)
wolffd@0 279 nj = ni{j};
wolffd@0 280 pj = pi{j};
wolffd@0 281 clj = cli{j};
wolffd@0 282 if wrp
wolffd@0 283 n2j = zeros(option.res,size(nj,2),size(nj,3));
wolffd@0 284 for k = 1:size(pj,1)
wolffd@0 285 n2j(clj(k)+1,:,:) = n2j(clj(k)+1,:,:) + nj(k,:,:); % squared sum (parameter)
wolffd@0 286 end
wolffd@0 287 p2i{j} = chromascale';
wolffd@0 288 else
wolffd@0 289 n2j = nj;
wolffd@0 290 p2i{j} = pi{j};
wolffd@0 291 end
wolffd@0 292 if option.cen
wolffd@0 293 n2j = n2j - repmat(mean(n2j),[size(n2j,1),1,1]);
wolffd@0 294 end
wolffd@0 295 if option.nor
wolffd@0 296 n2j = n2j ./ repmat(vectnorm(n2j,option.nor) + ...
wolffd@0 297 repmat(1e-6,[1,size(n2j,2),size(n2j,3)] )...
wolffd@0 298 ,[size(n2j,1),1,1]);
wolffd@0 299 end
wolffd@0 300 n2i{j} = n2j;
wolffd@0 301 end
wolffd@0 302 n2{i} = n2i;
wolffd@0 303 p2{i} = p2i;
wolffd@0 304 end
wolffd@0 305 c = set(c,'Magnitude',n2,'Chroma',p2,'FramePos',fp);
wolffd@0 306 end
wolffd@0 307
wolffd@0 308
wolffd@0 309 function c = freq2chro(f,res,origin)
wolffd@0 310 c = round(res*log2(f/origin));
wolffd@0 311
wolffd@0 312
wolffd@0 313 function f = chro2freq(c,res,origin)
wolffd@0 314 f = 2.^(c/res)*origin;
wolffd@0 315
wolffd@0 316
wolffd@0 317 function y = vectnorm(x,p)
wolffd@0 318 if isinf(p)
wolffd@0 319 y = max(x);
wolffd@0 320 else
wolffd@0 321 y = sum(abs(x).^p).^(1/p);
wolffd@0 322 end