Mercurial > hg > x
comparison multires.cpp @ 1:6422640a802f
first upload
author | Wen X <xue.wen@elec.qmul.ac.uk> |
---|---|
date | Tue, 05 Oct 2010 10:45:57 +0100 |
parents | |
children | 5f3c32dc6e17 |
comparison
equal
deleted
inserted
replaced
0:9b9f21935f24 | 1:6422640a802f |
---|---|
1 //--------------------------------------------------------------------------- | |
2 | |
3 | |
4 #include <math.h> | |
5 #include "multires.h" | |
6 #include "arrayalloc.h" | |
7 #include "procedures.h" | |
8 | |
9 //--------------------------------------------------------------------------- | |
10 | |
11 //function xlogx(x): returns x*log(x) | |
12 inline double xlogx(double x) | |
13 { | |
14 if (x==0) return 0; | |
15 else return x*log(x); | |
16 }//xlogx | |
17 | |
18 //macro NORMAL_: a normalization step used for tiling | |
19 #define NORMAL_(A, a) A=a*(A+log(a)); | |
20 // #define NORMAL_(A, a) A=a*a*A; | |
21 // #define NORMAL_(A, a) A=sqrt(a)*A; | |
22 | |
23 /* | |
24 function DoCutSpectrogramSquare: find optimal tiling of a square. This is a recursive procedure. | |
25 | |
26 In: Specs[0][1][N], Specs[1][2][N/2], ..., Specs[log2(N)][N][1], multiresolution power spectrogram | |
27 e[Res]: total power of each level, e[i] equals the sum of Specs[i][][] | |
28 NN: maximal tile height | |
29 Out: cuts[N-1]: the tiling result | |
30 ents[Res] | |
31 | |
32 Returns the entropy of the output tiling. | |
33 */ | |
34 double DoCutSpectrogramSquare(int* cuts, double*** Specs, double* e, int N, int NN, bool Norm, double* ents) | |
35 { | |
36 double result; | |
37 int Res=log2(N)+1; | |
38 | |
39 if (N==1) // 1*1 only(no cuts), returns the sample function. | |
40 { | |
41 double sp00; | |
42 if (e[0]!=0) sp00=Specs[0][0][0]/e[0]; else sp00=0; | |
43 ents[0]=xlogx(sp00); | |
44 return ents[0]; | |
45 } | |
46 else if (N==2) | |
47 { | |
48 double sp00, sp01, sp10, sp11; | |
49 if (e[0]!=0) sp00=Specs[0][0][0]/e[0], sp01=Specs[0][0][1]/e[0]; else sp00=sp01=0; | |
50 if (e[1]!=0) sp10=Specs[1][0][0]/e[1], sp11=Specs[1][1][0]/e[1]; else sp10=sp11=0; | |
51 double ent0=xlogx(sp00)+xlogx(sp01); | |
52 double ent1=xlogx(sp10)+xlogx(sp11); | |
53 if (ent0<ent1) | |
54 { | |
55 cuts[0]=1; | |
56 ents[0]=0, ents[1]=ent1; | |
57 } | |
58 else | |
59 { | |
60 cuts[0]=0; | |
61 ents[0]=ent0, ents[1]=0; | |
62 } | |
63 } | |
64 else | |
65 { | |
66 int* tmpcuts=new int[N-2]; | |
67 int *lcuts, *rcuts; | |
68 double ***lSpecs, ***rSpecs, *el, *er, ent0, ent1, a; | |
69 double *entl0=new double[Res-1], *entr0=new double[Res-1], | |
70 *entl1=new double[Res-1], *entr1=new double[Res-1]; | |
71 //vertical cuts: l->left half, r->right half | |
72 if (N<=NN) | |
73 { | |
74 lcuts=&cuts[1], rcuts=&cuts[N/2]; | |
75 VSplitSpecs(N, Specs, lSpecs, rSpecs); | |
76 el=new double[Res-1], er=new double[Res-1]; | |
77 memset(el, 0, sizeof(double)*(Res-1)); memset(er, 0, sizeof(double)*(Res-1)); | |
78 if (Norm) | |
79 { | |
80 //normalization | |
81 for (int i=0, Fr=1, n=N/2; i<Res-1; i++, Fr*=2, n/=2) | |
82 for (int j=0; j<Fr; j++) for (int k=0; k<n; k++) | |
83 el[i]+=lSpecs[i][j][k], er[i]+=rSpecs[i][j][k]; | |
84 } | |
85 else | |
86 for (int i=0; i<Res-1; i++) el[i]=er[i]=1; | |
87 | |
88 DoCutSpectrogramSquare(lcuts, lSpecs, el, N/2, NN, Norm, entl1); | |
89 DoCutSpectrogramSquare(rcuts, rSpecs, er, N/2, NN, Norm, entr1); | |
90 | |
91 ent1=0; | |
92 | |
93 for (int i=0; i<Res-1; i++) | |
94 { | |
95 if (e[i]!=0) | |
96 { | |
97 a=el[i]/e[i]; if (a>0) {NORMAL_(entl1[i], a);} else entl1[i]=0; ent1=ent1+entl1[i]; | |
98 a=er[i]/e[i]; if (a>0) {NORMAL_(entr1[i], a);} else entr1[i]=0; ent1=ent1+entr1[i]; | |
99 } | |
100 else | |
101 entl1[i]=entr1[i]=0; | |
102 } | |
103 | |
104 DeAlloc2(lSpecs); DeAlloc2(rSpecs); | |
105 delete[] el; delete[] er; | |
106 | |
107 } | |
108 //horizontal cuts: l->lower half, r->upper half | |
109 lcuts=tmpcuts, rcuts=&tmpcuts[N/2-1]; | |
110 HSplitSpecs(N, Specs, lSpecs, rSpecs); | |
111 el=new double[Res-1], er=new double[Res-1]; | |
112 memset(el, 0, sizeof(double)*(Res-1)); memset(er, 0, sizeof(double)*(Res-1)); | |
113 if (Norm) | |
114 { | |
115 //normalization | |
116 for (int i=0, Fr=1, n=N/2; i<Res-1; i++, Fr*=2, n/=2) | |
117 for (int j=0; j<Fr; j++) for (int k=0; k<n; k++) | |
118 el[i]+=lSpecs[i][j][k], er[i]+=rSpecs[i][j][k]; | |
119 } | |
120 else | |
121 for (int i=0; i<Res-1; i++) el[i]=er[i]=1; | |
122 | |
123 DoCutSpectrogramSquare(lcuts, lSpecs, el, N/2, NN, Norm, entl0); | |
124 DoCutSpectrogramSquare(rcuts, rSpecs, er, N/2, NN, Norm, entr0); | |
125 | |
126 ent0=0; | |
127 | |
128 if (Norm) | |
129 for (int i=0; i<Res-1; i++) | |
130 { | |
131 if (e[i]!=0) | |
132 { | |
133 a=el[i]/e[i]; if (a>0) {NORMAL_(entl0[i], a);} else entl0[i]=0; ent0=ent0+entl0[i]; | |
134 a=er[i]/e[i]; if (a>0) {NORMAL_(entr0[i], a);} else entr0[i]=0; ent0=ent0+entr0[i]; | |
135 } | |
136 else | |
137 entl0[i]=entr0[i]=0; | |
138 } | |
139 | |
140 DeAlloc2(lSpecs); DeAlloc2(rSpecs); | |
141 delete[] el; delete[] er; | |
142 | |
143 if (N<=NN && ent0<ent1) | |
144 { | |
145 cuts[0]=1; | |
146 result=ent1; | |
147 for (int i=0; i<Res-1; i++) | |
148 { | |
149 ents[i+1]=entl1[i]+entr1[i]; | |
150 } | |
151 ents[0]=0; | |
152 } | |
153 else | |
154 { | |
155 memcpy(&cuts[1], tmpcuts, sizeof(int)*(N-2)); | |
156 cuts[0]=0; | |
157 result=ent0; | |
158 for (int i=0; i<Res-1; i++) | |
159 { | |
160 ents[i]=entl0[i]+entr0[i]; | |
161 } | |
162 ents[Res-1]=0; | |
163 } | |
164 | |
165 delete[] tmpcuts; | |
166 delete[] entl0; delete[] entl1; delete[] entr0; delete[] entr1; | |
167 } | |
168 | |
169 return result; | |
170 }//DoCutSpectrogramSquare | |
171 | |
172 /* | |
173 function DoMixSpectrogramSquare: renders a composite spectrogram on a pixel grid. This is a recursive | |
174 procedure. | |
175 | |
176 In: Specs[0][1][N], Specs[1][2][N/2], Specs[2][4][N/4], ..., Specs[][N][1]: multiresolution power | |
177 spectrogram | |
178 cuts[N-1]: tiling | |
179 X, Y: dimensions of pixel grid to render | |
180 Out: Spec[X][Y]: pixel grid rendered to represent the given spectrograms and tiling | |
181 | |
182 No return value; | |
183 */ | |
184 void DoMixSpectrogramSquare(double** Spec, int* cuts, double*** Specs, int N, bool Norm, int X=0, int Y=0) | |
185 { | |
186 if (X==0 && Y==0) X=Y=N; | |
187 | |
188 if (N==1) | |
189 { | |
190 double value=Specs[0][0][0];//sqrt(Specs[0][0][0]); | |
191 value=value; | |
192 for (int x=0; x<X; x++) for (int y=0; y<Y; y++) Spec[x][y]=value; | |
193 } | |
194 else | |
195 { | |
196 double* e; | |
197 int Res; | |
198 | |
199 if (Norm) | |
200 { | |
201 //normalization | |
202 Res=log2(N)+1; | |
203 e=new double[Res]; | |
204 memset(e, 0, sizeof(double)*Res); | |
205 for (int i=0, Fr=1, n=N; i<Res; i++, Fr*=2, n/=2) | |
206 for (int j=0; j<Fr; j++) | |
207 for (int k=0; k<n; k++) | |
208 e[i]+=Specs[i][j][k]; | |
209 double em=e[0]; | |
210 for (int i=1; i<Res; i++) | |
211 { | |
212 if (e[i]>em) e[i]=em/e[i]; | |
213 else e[i]=1; | |
214 if (e[i]>em) em=e[i]; | |
215 } e[0]=1; | |
216 for (int i=0, Fr=1, n=N; i<Res; i++, Fr*=2, n/=2) | |
217 { | |
218 if (e[i]!=0 && e[1]!=1) | |
219 for (int j=0; j<Fr; j++) | |
220 for (int k=0; k<n; k++) | |
221 Specs[i][j][k]*=e[i]; | |
222 } | |
223 } | |
224 | |
225 double **lSpec, **rSpec, ***lSpecs, ***rSpecs; | |
226 if (cuts[0]) //1: vertical split | |
227 { | |
228 VSplitSpecs(N, Specs, lSpecs, rSpecs); | |
229 VSplitSpec(X, Y, Spec, lSpec, rSpec); | |
230 DoMixSpectrogramSquare(lSpec, &cuts[1], lSpecs, N/2, Norm, X/2, Y); | |
231 DoMixSpectrogramSquare(rSpec, &cuts[N/2], rSpecs, N/2, Norm, X/2, Y); | |
232 } | |
233 else //0: horizontal split | |
234 { | |
235 HSplitSpecs(N, Specs, lSpecs, rSpecs); | |
236 HSplitSpec(X, Y, Spec, lSpec, rSpec); | |
237 DoMixSpectrogramSquare(lSpec, &cuts[1], lSpecs, N/2, Norm, X, Y/2); | |
238 DoMixSpectrogramSquare(rSpec, &cuts[N/2], rSpecs, N/2, Norm, X, Y/2); | |
239 } | |
240 | |
241 if (Norm) | |
242 { | |
243 for (int i=0, Fr=1, n=N; i<Res; i++, Fr*=2, n/=2) | |
244 { | |
245 if (e[i]!=0 && e[1]!=1) | |
246 for (int j=0; j<Fr; j++) | |
247 for (int k=0; k<n; k++) | |
248 Specs[i][j][k]/=e[i]; | |
249 } | |
250 delete[] e; | |
251 } | |
252 | |
253 delete[] lSpec; delete[] rSpec; DeAlloc2(lSpecs); DeAlloc2(rSpecs); | |
254 } | |
255 }//DoMixSpectrogramSquare | |
256 | |
257 /* | |
258 function DoMixSpectrogramSquare: retrieves a composite spectrogram as a vector. This is a recursive | |
259 procedure. | |
260 | |
261 In: Specs[0][1][N], Specs[1][2][N/2], Specs[2][4][N/4], ..., Specs[][N][1]: multiresolution power | |
262 spectrogram | |
263 cuts[N-1]: tiling | |
264 Out: Spec[N]: composite spectrogram sampled fron Specs according to tiling cut[] | |
265 | |
266 No return value; | |
267 */ | |
268 void DoMixSpectrogramSquare(double* Spec, int* cuts, double*** Specs, int N, bool Norm) | |
269 { | |
270 // if (X==0 && Y==0) X=Y=N; | |
271 | |
272 if (N==1) | |
273 Spec[0]=Specs[0][0][0];//sqrt(Specs[0][0][0]); | |
274 else | |
275 { | |
276 double* e; | |
277 int Res; | |
278 | |
279 //Norm=false; | |
280 if (Norm) | |
281 { | |
282 //normalization | |
283 Res=log2(N)+1; | |
284 e=new double[Res]; | |
285 memset(e, 0, sizeof(double)*Res); | |
286 for (int i=0, Fr=1, n=N; i<Res; i++, Fr*=2, n/=2) | |
287 for (int j=0; j<Fr; j++) | |
288 for (int k=0; k<n; k++) | |
289 e[i]+=Specs[i][j][k]; | |
290 double em=e[0]; | |
291 for (int i=1; i<Res; i++) | |
292 { | |
293 if (e[i]>em) e[i]=em/e[i]; | |
294 else e[i]=1; | |
295 if (e[i]>em) em=e[i]; | |
296 } e[0]=1; | |
297 for (int i=0, Fr=1, n=N; i<Res; i++, Fr*=2, n/=2) | |
298 { | |
299 if (e[i]!=0 && e[i]!=1) | |
300 for (int j=0; j<Fr; j++) | |
301 for (int k=0; k<n; k++) | |
302 Specs[i][j][k]*=e[i]; | |
303 } | |
304 } | |
305 | |
306 double ***lSpecs, ***rSpecs; | |
307 if (cuts[0]) //1: vertical split | |
308 { | |
309 VSplitSpecs(N, Specs, lSpecs, rSpecs); | |
310 DoMixSpectrogramSquare(Spec, &cuts[1], lSpecs, N/2, Norm); | |
311 DoMixSpectrogramSquare(&Spec[N/2], &cuts[N/2], rSpecs, N/2, Norm); | |
312 } | |
313 else //0: horizontal split | |
314 { | |
315 HSplitSpecs(N, Specs, lSpecs, rSpecs); | |
316 DoMixSpectrogramSquare(Spec, &cuts[1], lSpecs, N/2, Norm); | |
317 DoMixSpectrogramSquare(&Spec[N/2], &cuts[N/2], rSpecs, N/2, Norm); | |
318 } | |
319 | |
320 if (Norm) | |
321 { | |
322 for (int i=0, Fr=1, n=N; i<Res; i++, Fr*=2, n/=2) | |
323 { | |
324 if (e[i]!=0 && e[1]!=1) | |
325 for (int j=0; j<Fr; j++) | |
326 for (int k=0; k<n; k++) | |
327 Specs[i][j][k]/=e[i]; | |
328 } | |
329 delete[] e; | |
330 } | |
331 | |
332 DeAlloc2(lSpecs); DeAlloc2(rSpecs); | |
333 } | |
334 }//DoMixSpectrogramSquare | |
335 | |
336 //--------------------------------------------------------------------------- | |
337 /* | |
338 function HSplitSpec: split a spectrogram horizontally into lower and upper halves. | |
339 | |
340 In: Spec[X][Y]: spectrogram to split | |
341 Out: lSpec[X][Y/2], uSpec[X][Y/2]: the two half spectrograms | |
342 | |
343 No return value. Both lSpec and uSpec are allocated anew. The caller is responsible to free these | |
344 buffers. | |
345 */ | |
346 void HSplitSpec(int X, int Y, double** Spec, double**& lSpec, double**& uSpec) | |
347 { | |
348 lSpec=new double*[X], uSpec=new double*[X]; | |
349 for (int i=0; i<X; i++) | |
350 lSpec[i]=Spec[i], uSpec[i]=&Spec[i][Y/2]; | |
351 }//HSplitSpec | |
352 | |
353 /* | |
354 function HSplitSpecs: split a multiresolution spectrogram horizontally into lower and upper halves | |
355 | |
356 A full spectrogram array is given in log2(N)+1 spectrograms, with the base spec of 1*N, 1st octave of | |
357 2*(N/2), ..., last octave of N*1. When this array is split into two spectrogram arrays horizontally, | |
358 the last spec (with the highest time resolution). Each of the two new arrays is given in log2(N) | |
359 spectrograms. | |
360 | |
361 In: Specs[nRes+1][][]: multiresolution spectrogram | |
362 Out: lSpecs[nRes][][], uSpecs[nRes][][], the two half multiresolution spectrograms | |
363 | |
364 This function allocates two 2nd order arrays of double*, which the caller is responsible to free. | |
365 */ | |
366 void HSplitSpecs(int N, double*** Specs, double***& lSpecs, double***& uSpecs) | |
367 { | |
368 int nRes=log2(N); // new number of resolutions | |
369 lSpecs=new double**[nRes], uSpecs=new double**[nRes]; | |
370 lSpecs[0]=new double*[nRes*N/2], uSpecs[0]=new double*[nRes*N/2]; for (int i=1; i<nRes; i++) lSpecs[i]=&lSpecs[0][i*N/2], uSpecs[i]=&uSpecs[0][i*N/2]; | |
371 for (int i=0, Fr=1, n=N; i<nRes; i++, Fr*=2, n/=2) | |
372 for (int j=0; j<Fr; j++) lSpecs[i][j]=Specs[i][j], uSpecs[i][j]=&Specs[i][j][n/2]; | |
373 }//HSplitSpecs | |
374 | |
375 //--------------------------------------------------------------------------- | |
376 /* | |
377 function MixSpectrogramSquare: find composite spectrogram from multiresolution spectrogram,output as | |
378 pixel grid | |
379 | |
380 In: Specs[0][1][N], Specs[1][2][N/2], ..., Specs[Res-1][N][1], multiresolution spectrogram | |
381 Out: Spec[N][N]: composite spectrogram as pixel grid (N time redundant) | |
382 cuts[N-1] (optional): tiling | |
383 | |
384 Returns entropy. | |
385 */ | |
386 double MixSpectrogramSquare(double** Spec, double*** Specs, int N, int Res, bool Norm, bool NormMix, int* cuts=0) | |
387 { | |
388 int tRes=log2(N)+1; | |
389 if (Res==0) Res=tRes; | |
390 int NN=1<<(Res-1); | |
391 bool createcuts=(cuts==0); | |
392 if (createcuts) cuts=new int[N]; | |
393 double* e=new double[tRes], *ents=new double[tRes]; | |
394 //normalization | |
395 memset(e, 0, sizeof(double)*Res); | |
396 for (int i=0, Fr=1, n=N; i<tRes; i++, Fr*=2, n/=2) | |
397 for (int j=0; j<Fr; j++) | |
398 for (int k=0; k<n; k++) | |
399 e[i]+=Specs[i][j][k]; | |
400 | |
401 if (!Norm) | |
402 { | |
403 for (int i=0, Fr=1, n=N; i<tRes; i++, Fr*=2, n/=2) | |
404 { | |
405 if (e[i]!=0 && e[i]!=1) | |
406 for (int j=0; j<Fr; j++) | |
407 for (int k=0; k<n; k++) | |
408 Specs[i][j][k]/=e[i]; | |
409 } | |
410 // for (int i=0; i<Res; i++) e[i]=1; | |
411 } | |
412 | |
413 double result=DoCutSpectrogramSquare(cuts, Specs, e, N, NN, Norm, ents); | |
414 delete[] ents; | |
415 | |
416 if (!Norm) | |
417 { | |
418 for (int i=0, Fr=1, n=N; i<tRes; i++, Fr*=2, n/=2) | |
419 { | |
420 if (e[i]!=0 && e[i]!=1) | |
421 for (int j=0; j<Fr; j++) | |
422 for (int k=0; k<n; k++) | |
423 Specs[i][j][k]*=e[i]; | |
424 } | |
425 } | |
426 DoMixSpectrogramSquare(Spec, cuts, Specs, N, NormMix, N, N); | |
427 | |
428 delete[] e; | |
429 if (createcuts) delete[] cuts; | |
430 return result; | |
431 }//MixSpectrogramSquare | |
432 | |
433 //--------------------------------------------------------------------------- | |
434 /* | |
435 function MixSpectrogramSquare: find composite spectrogram from multiresolution spectrogram,output as | |
436 vectors | |
437 | |
438 In: Specs[0][1][N], Specs[1][2][N/2], ..., Specs[Res-1][N][1], multiresolution spectrogram | |
439 Out: spl[N-1], Spec[N]: composite spectrogram as tiling and value vectors | |
440 | |
441 Returns entropy. | |
442 */ | |
443 double MixSpectrogramSquare(int* spl, double* Spec, double*** Specs, int N, int Res, bool Norm, bool NormMix) | |
444 { | |
445 int tRes=log2(N)+1; | |
446 if (Res==0) Res=tRes; | |
447 int NN=1<<(Res-1); | |
448 | |
449 double* e=new double[tRes], *ents=new double[tRes]; | |
450 | |
451 //normalization | |
452 memset(e, 0, sizeof(double)*Res); | |
453 for (int i=0, Fr=1, n=N; i<tRes; i++, Fr*=2, n/=2) | |
454 for (int j=0; j<Fr; j++) | |
455 for (int k=0; k<n; k++) | |
456 e[i]+=Specs[i][j][k]; | |
457 | |
458 if (!Norm) | |
459 { | |
460 for (int i=0, Fr=1, n=N; i<tRes; i++, Fr*=2, n/=2) | |
461 { | |
462 if (e[i]!=0 && e[i]!=1) | |
463 for (int j=0; j<Fr; j++) | |
464 for (int k=0; k<n; k++) | |
465 Specs[i][j][k]/=e[i]; | |
466 } | |
467 // for (int i=0; i<Res; i++) e[i]=1; | |
468 } | |
469 | |
470 double result=DoCutSpectrogramSquare(spl, Specs, e, N, NN, Norm, ents); | |
471 delete[] ents; | |
472 if (!Norm) | |
473 { | |
474 for (int i=0, Fr=1, n=N; i<tRes; i++, Fr*=2, n/=2) | |
475 { | |
476 if (e[i]!=0 && e[i]!=1) | |
477 for (int j=0; j<Fr; j++) | |
478 for (int k=0; k<n; k++) | |
479 Specs[i][j][k]*=e[i]; | |
480 } | |
481 } | |
482 DoMixSpectrogramSquare(Spec, spl, Specs, N, NormMix); | |
483 return result; | |
484 }//MixSpectrogramSquare | |
485 | |
486 //--------------------------------------------------------------------------- | |
487 /* | |
488 function MixSpectrogramBlock: obtain the composite spectrogram of a waveform block as pixel grid. | |
489 | |
490 This method deals with the effective duration of WID/2 samples of a frame of WID samples. The maximal | |
491 frame width is WID, minimal frame width is wid. The spectrum with frame width WID (base) is given in | |
492 lSpecs[0][0], the spectra with frame width WID/2 (1st octave) is given in lSpecs[1][0] & lSpecs[1][1], | |
493 etc. | |
494 | |
495 The output Spec[WID/wid][WID] is a spectrogram sampled from lSpecs, with a redundancy factor WID/wid. | |
496 The sampling is optimized so that a maximal entropy is achieved globally. This maximal entropy is | |
497 returned. | |
498 | |
499 In: Specs[0][1][WID], Specs[1][2][WID/2], ..., Specs[Res-1][WID/wid][wid], multiresolution spectrogram | |
500 Out: Spec[WID/wid][WID], composite spectrogram as pixel grid | |
501 cuts[wid][WID/wid-1] (optional), tilings of the wid squares the block is divided into. | |
502 | |
503 Returns entropy. | |
504 */ | |
505 double MixSpectrogramBlock(double** Spec, double*** Specs, int WID, int wid, bool norm, bool normmix, int** cuts=0) | |
506 { | |
507 int N=WID/wid, Res=log2(WID/wid)+1; | |
508 double result=0, **lSpec=new double*[N], ***lSpecs=new double**[Res]; | |
509 lSpecs[0]=new double*[Res*N]; for (int i=1; i<Res; i++) lSpecs[i]=&lSpecs[0][i*N]; | |
510 | |
511 bool createcuts=(cuts==0); | |
512 if (createcuts) | |
513 { | |
514 cuts=new int*[wid]; | |
515 memset(cuts, 0, sizeof(int*)*wid); | |
516 } | |
517 | |
518 for (int i=0; i<wid; i++) | |
519 { | |
520 for (int j=0; j<N; j++) | |
521 lSpec[j]=&Spec[j][i*N]; | |
522 for (int j=0, n=N, Fr=1; j<Res; j++, n/=2, Fr*=2) | |
523 { | |
524 for (int k=0; k<Fr; k++) | |
525 lSpecs[j][k]=&Specs[j][k][i*n]; | |
526 } | |
527 | |
528 int Log2N=log2(N); | |
529 if (i==0) | |
530 result+=MixSpectrogramSquare(lSpec, lSpecs, N, Log2N>2?(log2(N)-1):2, norm, normmix, cuts[i]); | |
531 else if (i==1) | |
532 result+=MixSpectrogramSquare(lSpec, lSpecs, N, Log2N>1?Log2N:2, norm, normmix, cuts[i]); | |
533 else | |
534 result+=MixSpectrogramSquare(lSpec, lSpecs, N, Log2N+1, norm, normmix, cuts[i]); | |
535 } | |
536 delete[] lSpec; | |
537 DeAlloc2(lSpecs); | |
538 if (createcuts) delete[] cuts; | |
539 return result; | |
540 }//MixSpectrogramBlock | |
541 | |
542 /* | |
543 function MixSpectrogramBlock: obtain the composite spectrogram of a waveform block as vectors. | |
544 | |
545 In: Specs[0][1][WID], Specs[1][2][WID/2], ..., Specs[Res-1][WID/wid][wid], multiresolution spectrogram | |
546 Out: spl[WID], Spec[WID], composite spectrogram as tiling and value vectors. Each of the vectors is | |
547 made up of $wid subvectors, each subvector pair describing a N*N block of the composite | |
548 spectrogram. | |
549 | |
550 Returns entropy. | |
551 */ | |
552 double MixSpectrogramBlock(int* spl, double* Spec, double*** Specs, int WID, int wid, bool norm, bool normmix) | |
553 { | |
554 int N=WID/wid, Res=log2(WID/wid)+1, *lspl; | |
555 double result=0, *lSpec, ***lSpecs=new double**[Res]; | |
556 lSpecs[0]=new double*[Res*N]; for (int i=1; i<Res; i++) lSpecs[i]=&lSpecs[0][i*N]; | |
557 | |
558 for (int i=0; i<wid; i++) | |
559 { | |
560 lspl=&spl[i*N]; | |
561 lSpec=&Spec[i*N]; | |
562 for (int j=0, n=N, Fr=1; j<Res; j++, n/=2, Fr*=2) | |
563 { | |
564 for (int k=0; k<Fr; k++) | |
565 lSpecs[j][k]=&Specs[j][k][i*n]; | |
566 } | |
567 int Log2N=log2(N); | |
568 /* | |
569 if (i==0) | |
570 result+=MixSpectrogramSquare(lspl, lSpec, lSpecs, N, Log2N>2?(log2(N)-1):2, norm, normmix); | |
571 else if (i==1) | |
572 result+=MixSpectrogramSquare(lspl, lSpec, lSpecs, N, Log2N>1?Log2N:2, norm, normmix); | |
573 else */ | |
574 result+=MixSpectrogramSquare(lspl, lSpec, lSpecs, N, Log2N+1, norm, normmix); | |
575 | |
576 } | |
577 DeAlloc2(lSpecs); | |
578 | |
579 return result; | |
580 }//MixSpectrogramBlock | |
581 | |
582 | |
583 //--------------------------------------------------------------------------- | |
584 /* | |
585 Functions names as ...Block2(...) implement the same functions as the above directly without | |
586 explicitly dividing the multiresolution spectrogram into square blocks. | |
587 */ | |
588 | |
589 /* | |
590 function DoCutSpectrogramBlock2: find optimal tiling for a block | |
591 | |
592 In: Specs[R0][x0:x0+x-1][Y0:Y0+Y-1], [R0+1][2x0:2x0+2x-1][Y0/2:Y0/2+Y/2-1],..., | |
593 Specs[R0+?][Nx0:Nx0+Nx-1][Y0/N:Y0/N+Y/N-1], multiresolution spectrogram | |
594 Out: spl[Y-1], tiling of this block | |
595 | |
596 Returns entropy. | |
597 */ | |
598 double DoCutSpectrogramBlock2(int* spl, double*** Specs, int Y, int R0, int x0, int Y0, int N, double& ene) | |
599 { | |
600 double ent=0; | |
601 if (Y>N) //N=WID/wid, the actual square size | |
602 { | |
603 spl[0]=0; | |
604 double ene1, ene2; | |
605 ent+=DoCutSpectrogramBlock2(&spl[1], Specs, Y/2, R0, x0, Y0, N, ene1); | |
606 ent+=DoCutSpectrogramBlock2(&spl[Y/2], Specs, Y/2, R0, x0, Y0+Y/2, N, ene2); | |
607 ene=ene1+ene2; | |
608 } | |
609 else if (N==1) | |
610 { | |
611 double tmp=Specs[R0][x0][Y0]; | |
612 ene=tmp; | |
613 ent=xlogx(tmp); | |
614 } | |
615 else //Y==N, the square case | |
616 { | |
617 double enel, ener, enet, eneb, entl, entr, entt, entb; | |
618 int* tmpspl=new int[Y]; | |
619 entl=DoCutSpectrogramBlock2(&spl[1], Specs, Y/2, R0+1, 2*x0, Y0/2, N/2, enel); | |
620 entr=DoCutSpectrogramBlock2(&spl[Y/2], Specs, Y/2, R0+1, 2*x0+1, Y0/2, N/2, ener); | |
621 entb=DoCutSpectrogramBlock2(&tmpspl[1], Specs, Y/2, R0, x0, Y0, N/2, eneb); | |
622 entt=DoCutSpectrogramBlock2(&tmpspl[Y/2], Specs, Y/2, R0, x0, Y0+Y/2, N/2, enet); | |
623 double ene0=enet+eneb, ene1=enel+ener, ent0=entt+entb, ent1=entl+entr; | |
624 //normalize | |
625 double eneres=1-(ene0+ene1)/2, norment0, norment1; | |
626 //double a0=1/(ene0+eneres), a1=1/(ene1+eneres); | |
627 //quasi-global normalization | |
628 norment0=(ent0-ene0*log(ene0+eneres))/(ene0+eneres), norment1=(ent1-ene1*log(ene1+eneres))/(ene1+eneres); | |
629 //local normalization | |
630 //if (ene0>0) norment0=ent0/ene0-log(ene0); else norment0=0; if (ene1>0) norment1=ent1/ene1-log(ene1); else norment1=0; | |
631 if (norment1<norment0) | |
632 { | |
633 spl[0]=0; | |
634 ent=ent0, ene=ene0; | |
635 memcpy(&spl[1], &tmpspl[1], sizeof(int)*(Y-2)); | |
636 } | |
637 else | |
638 { | |
639 spl[0]=1; | |
640 ent=ent1, ene=ene1; | |
641 } | |
642 } | |
643 return ent; | |
644 }//DoCutSpectrogramBlock2 | |
645 | |
646 /* | |
647 function DoMixSpectrogramBlock2: sampling multiresolution spectrogram according to given tiling | |
648 | |
649 In: Specs[R0][x0:x0+x-1][Y0:Y0+Y-1], [R0+1][2x0:2x0+2x-1][Y0/2:Y0/2+Y/2-1],..., | |
650 Specs[R0+?][Nx0:Nx0+Nx-1][Y0/N:Y0/N+Y/N-1], multiresolution spectrogram | |
651 spl[Y-1]; tiling of this block | |
652 Out: Spec[Y], composite spectrogram as value vector | |
653 | |
654 Returns 0. | |
655 */ | |
656 double DoMixSpectrogramBlock2(int* spl, double* Spec, double*** Specs, int Y, int R0, int x0, int Y0, bool normmix, int res, double* e) | |
657 { | |
658 if (Y==1) | |
659 { | |
660 Spec[0]=Specs[R0][x0][Y0]*e[0]; | |
661 } | |
662 else | |
663 { | |
664 double le[32]; | |
665 if (normmix && Y<(1<<res)) | |
666 { | |
667 for (int i=0, j=1, k=Y; i<res; i++, j*=2, k/=2) | |
668 { | |
669 double lle=0; | |
670 for (int fr=0; fr<j; fr++) for (int n=0; n<k; n++) lle+=Specs[i+R0][x0+fr][Y0+n]*Specs[i+R0][x0+fr][Y0+n]; | |
671 lle=sqrt(lle)*e[i]; | |
672 if (i==0) le[0]=lle; | |
673 else if (lle>le[0]*2) le[i]=e[i]*le[0]*2/lle; | |
674 else le[i]=e[i]; | |
675 } | |
676 le[0]=e[0]; | |
677 } | |
678 else | |
679 { | |
680 memcpy(le, e, sizeof(double)*res); | |
681 } | |
682 | |
683 if (spl[0]==0) | |
684 { | |
685 int newres; | |
686 if (Y>=(1<<res)) newres=res; | |
687 else newres=res-1; | |
688 DoMixSpectrogramBlock2(&spl[1], Spec, Specs, Y/2, R0, x0, Y0, normmix, newres, le); | |
689 DoMixSpectrogramBlock2(&spl[Y/2], &Spec[Y/2], Specs, Y/2, R0, x0, Y0+Y/2, normmix, newres, le); | |
690 } | |
691 else | |
692 { | |
693 DoMixSpectrogramBlock2(&spl[1], Spec, Specs, Y/2, R0+1, x0*2, Y0/2, normmix, res-1, &le[1]); | |
694 DoMixSpectrogramBlock2(&spl[Y/2], &Spec[Y/2], Specs, Y/2, R0+1, x0*2+1, Y0/2, normmix, res-1, &le[1]); | |
695 } | |
696 } | |
697 return 0; | |
698 }//DoMixSpectrogramBlock2 | |
699 | |
700 /* | |
701 function MixSpectrogramBlock2: obtain the composite spectrogram of a waveform block as vectors. | |
702 | |
703 In: Specs[0][1][WID], Specs[1][2][WID/2], ..., Specs[Res-1][WID/wid][wid], multiresolution spectrogram | |
704 Out: spl[WID], Spec[WID], composite spectrogram as tiling and value vectors. Each of the | |
705 vectors is made up of $wid subvectors, each subvector pair describing a N*N block of the | |
706 composite spectrogram. | |
707 | |
708 Returns entropy. | |
709 */ | |
710 double MixSpectrogramBlock2(int* spl, double* Spec, double*** Specs, int WID, int wid, bool normmix) | |
711 { | |
712 double ene[32]; | |
713 //find the total energy and normalize | |
714 for (int i=0, Fr=1, Wid=WID; Wid>=wid; i++, Fr*=2, Wid/=2) | |
715 { | |
716 double lene=0; | |
717 for (int fr=0; fr<Fr; fr++) for (int k=0; k<Wid; k++) lene+=Specs[i][fr][k]*Specs[i][fr][k]; | |
718 ene[i]=lene; | |
719 if (lene!=0) | |
720 { | |
721 double ilene=1.0/lene; | |
722 for (int fr=0; fr<Fr; fr++) for (int k=0; k<Wid; k++) Specs[i][fr][k]=Specs[i][fr][k]*Specs[i][fr][k]*ilene; | |
723 } | |
724 } | |
725 | |
726 double result=DoCutSpectrogramBlock2(spl, Specs, WID, 0, 0, 0, WID/wid, ene[31]); | |
727 | |
728 //de-normalize | |
729 for (int i=0, Fr=1, Wid=WID; Wid>=wid; i++, Fr*=2, Wid/=2) | |
730 { | |
731 double lene=ene[i]; | |
732 if (lene!=0) | |
733 for (int fr=0; fr<Fr; fr++) for (int k=0; k<Wid; k++) Specs[i][fr][k]=sqrt(Specs[i][fr][k]*lene); | |
734 } | |
735 | |
736 double e[32]; for (int i=0; i<32; i++) e[i]=1; | |
737 DoMixSpectrogramBlock2(spl, Spec, Specs, WID, 0, 0, 0, normmix, log2(WID/wid)+1, e); | |
738 return result; | |
739 }//MixSpectrogramBlock2 | |
740 | |
741 //--------------------------------------------------------------------------- | |
742 /* | |
743 function MixSpectrogram: obtain composite spectrogram from multiresolutin spectrogram as pixel grid | |
744 | |
745 This method deals with Fr (base) frames of WID samples. Each base frame may be divided into 2 1st- | |
746 octave frames, 4 2nd-octave frames, ..., etc. The spectrogram calculated on base frame is given in | |
747 Specs[0] (Fr frames); that of 1st octave is given in Specs[1] (2*Fr frames); etc. The method resamples | |
748 the spectrograms of different frame width into a single spectrogram so that the entropy is maximized | |
749 globally. | |
750 | |
751 The output Spec is a spectrogram of apparent resolution WID at hop size wid. It is a redundant | |
752 representation, with equal values occupying blocks of size WID/wid. | |
753 | |
754 In: Specs[0][Fr][WID], Specs[1][Fr*2][WID/2], ..., Specs[Res-1] [Fr*(WID/wid)][wid], multiresolution | |
755 spectrogram | |
756 Out: Spec[Fr*(WID/wid)][WID], composite spectrogram as pixel grid | |
757 cuts[Fr][wid][N=Wid/wid], tilings of small square blocks | |
758 Returns 0. | |
759 */ | |
760 double MixSpectrogram(double** Spec, double*** Specs, int Fr, int WID, int wid, bool norm, bool normmix, int*** cuts) | |
761 { | |
762 //totally Fr frames of WID samples | |
763 //each frame is divided into wid VERTICAL parts | |
764 bool createcuts=(cuts==0); | |
765 if (createcuts) | |
766 { | |
767 cuts=new int**[Fr]; | |
768 memset(cuts, 0, sizeof(int**)*Fr); | |
769 } | |
770 int Res=log2(WID/wid)+1; | |
771 double*** lSpecs=new double**[Res]; | |
772 for (int i=0; i<Fr; i++) | |
773 { | |
774 for (int j=0, nfr=1; j<Res; j++, nfr*=2) lSpecs[j]=&Specs[j][i*nfr]; | |
775 MixSpectrogramBlock(&Spec[i*WID/wid], lSpecs, WID, wid, norm, normmix, cuts[i]); | |
776 } | |
777 | |
778 delete[] lSpecs; | |
779 if (createcuts) delete[] cuts; | |
780 return 0; | |
781 }//MixSpectrogram | |
782 | |
783 /* | |
784 function MixSpectrogram: obtain composite spectrogram from multiresolutin spectrogram as vectors | |
785 | |
786 In: Specs[0][Fr][WID], Specs[1][Fr*2][WID/2], ..., Specs[Res-1] [Fr*(WID/wid)][wid], multiresolution | |
787 spectrogram | |
788 Out: spl[Fr][WID], Spec[Fr][WID], composite spectrogram as tiling and value vectors by frame. | |
789 | |
790 Returns 0. | |
791 */ | |
792 double MixSpectrogram(int** spl, double** Spec, double*** Specs, int Fr, int WID, int wid, bool norm, bool normmix) | |
793 { | |
794 //totally Fr frames of WID samples | |
795 //each frame is divided into wid VERTICAL parts | |
796 int Res=log2(WID/wid)+1; | |
797 double*** lSpecs=new double**[Res]; | |
798 for (int i=0; i<Fr; i++) | |
799 { | |
800 for (int j=0, nfr=1; j<Res; j++, nfr*=2) lSpecs[j]=&Specs[j][i*nfr]; | |
801 MixSpectrogramBlock(spl[i], Spec[i], lSpecs, WID, wid, norm, normmix); | |
802 // MixSpectrogramBlock2(spl[i], Spec[i], lSpecs, WID, wid, norm); | |
803 } | |
804 | |
805 delete[] lSpecs; | |
806 return 0; | |
807 }//MixSpectrogram | |
808 | |
809 //--------------------------------------------------------------------------- | |
810 /* | |
811 function VSplitSpec: split a spectrogram vertically into left and right halves. | |
812 | |
813 In: Spec[X][Y]: spectrogram to split | |
814 Out: lSpec[X][Y/2], rSpec[X][Y/2]: the two half spectrograms | |
815 | |
816 No return value. Both lSpec and rSpec are allocated anew. The caller is responsible to free these | |
817 buffers. | |
818 */ | |
819 void VSplitSpec(int X, int Y, double** Spec, double**& lSpec, double**& rSpec) | |
820 { | |
821 lSpec=new double*[X/2], rSpec=new double*[X/2]; | |
822 for(int i=0; i<X/2; i++) | |
823 lSpec[i]=Spec[i], rSpec[i]=Spec[i+X/2]; | |
824 }//VSplitSpec | |
825 | |
826 /* | |
827 function VSplitSpecs: split a multiresolution spectrogram vertically into left and right halves | |
828 | |
829 A full spectrogram array is given in log2(N)+1 spectrograms, with the base spec of 1*N, 1st octave of | |
830 2*(N/2), ..., last octave of N*1. When this array is split into two spectrogram arrays horizontally, | |
831 the last spec (with the highest time resolution). Each of the two new arrays is given in log2(N) | |
832 spectrograms. | |
833 | |
834 In: Specs[nRes+1][][]: multiresolution spectrogram | |
835 Out: lSpecs[nRes][][], rSpecs[nRes][][], the two half multiresolution spectrograms | |
836 | |
837 This function allocates two 2nd order arrays of double*, which the caller is responsible to free. | |
838 */ | |
839 void VSplitSpecs(int N, double*** Specs, double***& lSpecs, double***& rSpecs) | |
840 { | |
841 int nRes=log2(N); // new number of resolutions | |
842 lSpecs=new double**[nRes], rSpecs=new double**[nRes]; | |
843 lSpecs[0]=new double*[nRes*N/2], rSpecs[0]=new double*[nRes*N/2]; for (int i=1; i<nRes; i++) lSpecs[i]=&lSpecs[0][i*N/2], rSpecs[i]=&rSpecs[0][i*N/2]; | |
844 for (int i=0, Fr=1; i<nRes; i++, Fr*=2) | |
845 for (int j=0; j<Fr; j++) | |
846 lSpecs[i][j]=Specs[i+1][j], rSpecs[i][j]=Specs[i+1][j+Fr]; | |
847 }//VSplitSpecs | |
848 | |
849 |