annotate multires.cpp @ 13:de3961f74f30 tip

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