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