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