xue@11: /* xue@11: Harmonic sinusoidal modelling and tools xue@11: xue@11: C++ code package for harmonic sinusoidal modelling and relevant signal processing. xue@11: Centre for Digital Music, Queen Mary, University of London. xue@11: This file copyright 2011 Wen Xue. xue@11: xue@11: This program is free software; you can redistribute it and/or xue@11: modify it under the terms of the GNU General Public License as xue@11: published by the Free Software Foundation; either version 2 of the xue@11: License, or (at your option) any later version. xue@11: */ xue@1: //--------------------------------------------------------------------------- xue@1: xue@1: #include xue@1: #include "multires.h" xue@1: #include "arrayalloc.h" xue@1: #include "procedures.h" xue@1: Chris@5: /** \file multires.h */ Chris@5: xue@1: //--------------------------------------------------------------------------- xue@1: xue@1: //function xlogx(x): returns x*log(x) xue@1: inline double xlogx(double x) xue@1: { xue@1: if (x==0) return 0; xue@1: else return x*log(x); xue@1: }//xlogx xue@1: xue@1: //macro NORMAL_: a normalization step used for tiling xue@1: #define NORMAL_(A, a) A=a*(A+log(a)); xue@1: // #define NORMAL_(A, a) A=a*a*A; xue@1: // #define NORMAL_(A, a) A=sqrt(a)*A; xue@1: Chris@5: /** xue@1: function DoCutSpectrogramSquare: find optimal tiling of a square. This is a recursive procedure. xue@1: xue@1: In: Specs[0][1][N], Specs[1][2][N/2], ..., Specs[log2(N)][N][1], multiresolution power spectrogram xue@1: e[Res]: total power of each level, e[i] equals the sum of Specs[i][][] xue@1: NN: maximal tile height xue@1: Out: cuts[N-1]: the tiling result xue@1: ents[Res] xue@1: xue@1: Returns the entropy of the output tiling. xue@1: */ xue@1: double DoCutSpectrogramSquare(int* cuts, double*** Specs, double* e, int N, int NN, bool Norm, double* ents) xue@1: { xue@1: double result; xue@1: int Res=log2(N)+1; xue@1: xue@1: if (N==1) // 1*1 only(no cuts), returns the sample function. xue@1: { xue@1: double sp00; xue@1: if (e[0]!=0) sp00=Specs[0][0][0]/e[0]; else sp00=0; xue@1: ents[0]=xlogx(sp00); xue@1: return ents[0]; xue@1: } xue@1: else if (N==2) xue@1: { xue@1: double sp00, sp01, sp10, sp11; xue@1: if (e[0]!=0) sp00=Specs[0][0][0]/e[0], sp01=Specs[0][0][1]/e[0]; else sp00=sp01=0; xue@1: if (e[1]!=0) sp10=Specs[1][0][0]/e[1], sp11=Specs[1][1][0]/e[1]; else sp10=sp11=0; xue@1: double ent0=xlogx(sp00)+xlogx(sp01); xue@1: double ent1=xlogx(sp10)+xlogx(sp11); xue@1: if (ent0left half, r->right half xue@1: if (N<=NN) xue@1: { xue@1: lcuts=&cuts[1], rcuts=&cuts[N/2]; xue@1: VSplitSpecs(N, Specs, lSpecs, rSpecs); xue@1: el=new double[Res-1], er=new double[Res-1]; xue@1: memset(el, 0, sizeof(double)*(Res-1)); memset(er, 0, sizeof(double)*(Res-1)); xue@1: if (Norm) xue@1: { xue@1: //normalization xue@1: for (int i=0, Fr=1, n=N/2; i0) {NORMAL_(entl1[i], a);} else entl1[i]=0; ent1=ent1+entl1[i]; xue@1: a=er[i]/e[i]; if (a>0) {NORMAL_(entr1[i], a);} else entr1[i]=0; ent1=ent1+entr1[i]; xue@1: } xue@1: else xue@1: entl1[i]=entr1[i]=0; xue@1: } xue@1: xue@1: DeAlloc2(lSpecs); DeAlloc2(rSpecs); xue@1: delete[] el; delete[] er; xue@1: xue@1: } xue@1: //horizontal cuts: l->lower half, r->upper half xue@1: lcuts=tmpcuts, rcuts=&tmpcuts[N/2-1]; xue@1: HSplitSpecs(N, Specs, lSpecs, rSpecs); xue@1: el=new double[Res-1], er=new double[Res-1]; xue@1: memset(el, 0, sizeof(double)*(Res-1)); memset(er, 0, sizeof(double)*(Res-1)); xue@1: if (Norm) xue@1: { xue@1: //normalization xue@1: for (int i=0, Fr=1, n=N/2; i0) {NORMAL_(entl0[i], a);} else entl0[i]=0; ent0=ent0+entl0[i]; xue@1: a=er[i]/e[i]; if (a>0) {NORMAL_(entr0[i], a);} else entr0[i]=0; ent0=ent0+entr0[i]; xue@1: } xue@1: else xue@1: entl0[i]=entr0[i]=0; xue@1: } xue@1: xue@1: DeAlloc2(lSpecs); DeAlloc2(rSpecs); xue@1: delete[] el; delete[] er; xue@1: xue@1: if (N<=NN && ent0em) e[i]=em/e[i]; xue@1: else e[i]=1; xue@1: if (e[i]>em) em=e[i]; xue@1: } e[0]=1; xue@1: for (int i=0, Fr=1, n=N; iem) e[i]=em/e[i]; xue@1: else e[i]=1; xue@1: if (e[i]>em) em=e[i]; xue@1: } e[0]=1; xue@1: for (int i=0, Fr=1, n=N; i2?(log2(N)-1):2, norm, normmix, cuts[i]); xue@1: else if (i==1) xue@1: result+=MixSpectrogramSquare(lSpec, lSpecs, N, Log2N>1?Log2N:2, norm, normmix, cuts[i]); xue@1: else xue@1: result+=MixSpectrogramSquare(lSpec, lSpecs, N, Log2N+1, norm, normmix, cuts[i]); xue@1: } xue@1: delete[] lSpec; xue@1: DeAlloc2(lSpecs); xue@1: if (createcuts) delete[] cuts; xue@1: return result; xue@1: }//MixSpectrogramBlock xue@1: Chris@5: /** xue@1: function MixSpectrogramBlock: obtain the composite spectrogram of a waveform block as vectors. xue@1: xue@1: In: Specs[0][1][WID], Specs[1][2][WID/2], ..., Specs[Res-1][WID/wid][wid], multiresolution spectrogram xue@1: Out: spl[WID], Spec[WID], composite spectrogram as tiling and value vectors. Each of the vectors is xue@1: made up of $wid subvectors, each subvector pair describing a N*N block of the composite xue@1: spectrogram. xue@1: xue@1: Returns entropy. xue@1: */ xue@1: double MixSpectrogramBlock(int* spl, double* Spec, double*** Specs, int WID, int wid, bool norm, bool normmix) xue@1: { xue@1: int N=WID/wid, Res=log2(WID/wid)+1, *lspl; xue@1: double result=0, *lSpec, ***lSpecs=new double**[Res]; xue@1: lSpecs[0]=new double*[Res*N]; for (int i=1; i2?(log2(N)-1):2, norm, normmix); xue@1: else if (i==1) xue@1: result+=MixSpectrogramSquare(lspl, lSpec, lSpecs, N, Log2N>1?Log2N:2, norm, normmix); xue@1: else */ xue@1: result+=MixSpectrogramSquare(lspl, lSpec, lSpecs, N, Log2N+1, norm, normmix); xue@1: xue@1: } xue@1: DeAlloc2(lSpecs); xue@1: xue@1: return result; xue@1: }//MixSpectrogramBlock xue@1: xue@1: xue@1: //--------------------------------------------------------------------------- Chris@5: /** Chris@5: functions names as ...Block2(...) implement the same functions as the above directly without xue@1: explicitly dividing the multiresolution spectrogram into square blocks. xue@1: */ xue@1: Chris@5: /** xue@1: function DoCutSpectrogramBlock2: find optimal tiling for a block xue@1: xue@1: 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: Specs[R0+?][Nx0:Nx0+Nx-1][Y0/N:Y0/N+Y/N-1], multiresolution spectrogram xue@1: Out: spl[Y-1], tiling of this block xue@1: xue@1: Returns entropy. xue@1: */ xue@1: double DoCutSpectrogramBlock2(int* spl, double*** Specs, int Y, int R0, int x0, int Y0, int N, double& ene) xue@1: { xue@1: double ent=0; xue@1: if (Y>N) //N=WID/wid, the actual square size xue@1: { xue@1: spl[0]=0; xue@1: double ene1, ene2; xue@1: ent+=DoCutSpectrogramBlock2(&spl[1], Specs, Y/2, R0, x0, Y0, N, ene1); xue@1: ent+=DoCutSpectrogramBlock2(&spl[Y/2], Specs, Y/2, R0, x0, Y0+Y/2, N, ene2); xue@1: ene=ene1+ene2; xue@1: } xue@1: else if (N==1) xue@1: { xue@1: double tmp=Specs[R0][x0][Y0]; xue@1: ene=tmp; xue@1: ent=xlogx(tmp); xue@1: } xue@1: else //Y==N, the square case xue@1: { xue@1: double enel, ener, enet, eneb, entl, entr, entt, entb; xue@1: int* tmpspl=new int[Y]; xue@1: entl=DoCutSpectrogramBlock2(&spl[1], Specs, Y/2, R0+1, 2*x0, Y0/2, N/2, enel); xue@1: entr=DoCutSpectrogramBlock2(&spl[Y/2], Specs, Y/2, R0+1, 2*x0+1, Y0/2, N/2, ener); xue@1: entb=DoCutSpectrogramBlock2(&tmpspl[1], Specs, Y/2, R0, x0, Y0, N/2, eneb); xue@1: entt=DoCutSpectrogramBlock2(&tmpspl[Y/2], Specs, Y/2, R0, x0, Y0+Y/2, N/2, enet); xue@1: double ene0=enet+eneb, ene1=enel+ener, ent0=entt+entb, ent1=entl+entr; xue@1: //normalize xue@1: double eneres=1-(ene0+ene1)/2, norment0, norment1; xue@1: //double a0=1/(ene0+eneres), a1=1/(ene1+eneres); xue@1: //quasi-global normalization xue@1: norment0=(ent0-ene0*log(ene0+eneres))/(ene0+eneres), norment1=(ent1-ene1*log(ene1+eneres))/(ene1+eneres); xue@1: //local normalization xue@1: //if (ene0>0) norment0=ent0/ene0-log(ene0); else norment0=0; if (ene1>0) norment1=ent1/ene1-log(ene1); else norment1=0; xue@1: if (norment1le[0]*2) le[i]=e[i]*le[0]*2/lle; xue@1: else le[i]=e[i]; xue@1: } xue@1: le[0]=e[0]; xue@1: } xue@1: else xue@1: { xue@1: memcpy(le, e, sizeof(double)*res); xue@1: } xue@1: xue@1: if (spl[0]==0) xue@1: { xue@1: int newres; xue@1: if (Y>=(1<=wid; i++, Fr*=2, Wid/=2) xue@1: { xue@1: double lene=0; xue@1: for (int fr=0; fr=wid; i++, Fr*=2, Wid/=2) xue@1: { xue@1: double lene=ene[i]; xue@1: if (lene!=0) xue@1: for (int fr=0; fr