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 Chris@2: #include xue@1: #include "hssf.h" xue@1: #include "arrayalloc.h" Chris@2: #include "matrix.h" xue@1: #include "vibrato.h" xue@1: Chris@5: /** \file hssf.h */ Chris@5: xue@1: //--------------------------------------------------------------------------- xue@1: //method TSF::TSF: default constructor. xue@1: TSF::TSF() xue@1: { xue@1: memset(this, 0, sizeof(TSF)); xue@1: }//TSF xue@1: xue@1: //method TSF::~TSF: default destructor. xue@1: TSF::~TSF() xue@1: { xue@1: if (h) DeAlloc2(h); xue@1: if (b) DeAlloc2(b); xue@1: delete[] lp; xue@1: delete[] F0; xue@1: free(avgh); xue@1: free(avgb); xue@1: }//~TSF xue@1: Chris@5: /** xue@1: method TSF::AllocateL: allocates or reallocates storage space whose size depends on L. This uses an xue@1: external L value for allocation and updates L itself. xue@1: */ xue@1: void TSF::AllocateL(int AnL) xue@1: { xue@1: L=AnL; xue@1: delete[] F0; F0=new double[(L+2)*6]; xue@1: F0C=&F0[L+2], F0D=&F0[(L+2)*2], logA0C=&F0[(L+2)*3], logA0=&F0[(L+2)*4], logA0D=&F0[(L+2)*5]; xue@1: }//AllocateL xue@1: Chris@5: /** xue@1: method TSF::AllocateP: allocates or reallocates storage space whose size depends on P, using the xue@1: interal P. xue@1: */ xue@1: void TSF::AllocateP() xue@1: { xue@1: delete[] lp; xue@1: lp=new double[P+2]; xue@1: }//AllocateP xue@1: Chris@5: /** xue@1: method TSF::AllocateSF: allocates or reallocates storage space for source-filter coefficients. xue@1: */ xue@1: void TSF::AllocateSF() xue@1: { xue@1: if (h) DeAlloc2(h); int k=1.0/F; Allocate2(double, L, (k+2), h); memset(h[0], 0, sizeof(double)*(L)*(k+2)); xue@1: if (b) DeAlloc2(b); Allocate2(double, L, M, b); memset(b[0], 0, sizeof(double)*(L)*M); xue@1: avgh=(double*)realloc(avgh, sizeof(double)*(k+2)); avgb=(double*)realloc(avgb, sizeof(double)*M); xue@1: }//AllocateSF xue@1: Chris@5: /** xue@1: method TSF::Duplicate: copies the complete contents from another SF object xue@1: xue@1: In: SF: source object xue@1: */ xue@1: void TSF::Duplicate(TSF& SF) xue@1: { Chris@13: this->TSF::~TSF(); xue@1: memcpy(this, &SF, sizeof(TSF)); lp=F0=avgh=avgb=0, h=b=0; xue@1: AllocateL(L); memcpy(F0, SF.F0, sizeof(double)*(L+2)*6); xue@1: AllocateP(); memcpy(lp, SF.lp, sizeof(double)*(P+2)); xue@1: AllocateSF(); int SFL=ceil(lp[P-1])-ceil(lp[0]); xue@1: for (int l=0; l=lpp-lp0) l=lpp-lp0-1; xue@1: if (FScaleMode) f=log(1+f*Fs/700)/log(1+Fs/700); xue@1: int k=floor(f/F); xue@1: double f_plus=f/F-k; xue@1: if (k=lpp-lp0) l=lpp-lp0-1; xue@1: return b[l][m]; xue@1: }//LogAS xue@1: Chris@5: /** xue@1: method TSF::ReAllocateL: reallocates storage space whose size depends on L, and transfer the contents. xue@1: This uses an external L value for allocation but does not update L itself. xue@1: */ xue@1: void TSF::ReAllocateL(int newL) xue@1: { xue@1: double* newF0=new double[(newL+2)*4]; F0C=&newF0[newL+2], F0D=&newF0[(newL+2)*2], logA0C=&newF0[(newL+2)*3], logA0=&newF0[(L+2)*4], logA0D=&F0[(L+2)*5]; xue@1: memcpy(logA0C, &F0[(L+2)*3], sizeof(double)*(L+2)); xue@1: memcpy(logA0D, &F0[(L+2)*5], sizeof(double)*(L+2)); xue@1: memcpy(F0D, &F0[(L+2)*2], sizeof(double)*(L+2)); xue@1: memcpy(F0C, &F0[L+2], sizeof(double)*(L+2)); xue@1: memcpy(newF0, F0, sizeof(double)*(L+2)); xue@1: delete[] F0; xue@1: F0=newF0; xue@1: }//ReAllocateL xue@1: Chris@5: /** xue@1: method TSF::SaveSFToFileHandle: writes SF coefficients to file xue@1: */ xue@1: void TSF::SaveSFToFileHandle(FILE* f) xue@1: { xue@1: fwrite(&K, sizeof(int), 1, f); xue@1: fwrite(&FScaleMode, sizeof(int), 1, f); xue@1: fwrite(&F, sizeof(double), 1, f); xue@1: fwrite(&Fs, sizeof(double), 1, f); xue@1: for (int l=0; lSF.F0[fr]) SF.F0min=SF.F0[fr]; xue@1: A0[fr]=suma2; xue@1: } xue@1: xue@1: //Basic descriptor: M xue@1: SF.M=0.45/SF.F0max; xue@1: if (SF.M>M) SF.M=M; xue@1: xue@1: //rough estimation of rate xue@1: double* f0d=new double[Fr-1]; for (int i=0; i=1) //de-modulation xue@1: { xue@1: //Basic descriptor: F0C[] xue@1: DeFM(SF.F0C, SF.F0, SF.logA0, SF.P, SF.lp, Fr, SF.F0Overall, *cyclefrcount, cyclefrs, cyclefs); xue@1: //Basic descriptor: A0C[] xue@1: double *A0C=SF.logA0C, *logA0C=SF.logA0C, *logA0D=SF.logA0D, *logA0=SF.logA0; xue@1: DeAM(A0C, SF.logA0, SF.P, SF.lp, Fr); xue@1: for (int fr=0; frSF.F0C[fr]) SF.F0Cmin=SF.F0C[fr]; xue@1: SF.F0D[fr]=SF.F0[fr]-SF.F0C[fr]; xue@1: } xue@1: xue@1: //Basic descriptor: b, h xue@1: //Source-filter modeling xue@1: { xue@1: SF.F=SFF; SF.Fs=sps; SF.AllocateSF(); xue@1: int M=SF.M; double **h=SF.h, **b=SF.b;// *avgh=SF.avgh, *avgb=SF.avgb; xue@1: xue@1: double *logA0C=useA0?SF.logA0:SF.logA0C; xue@1: if (SFMode==0){ xue@1: S_F_FB(M, Partials, logA0C, SF.lp, SF.P, SF.K, h, SF.avgh, b, SF.avgb, SFF, SFFScale, sps);} xue@1: else if (SFMode==1){ xue@1: S_F_SV(M, Partials, logA0C, SF.lp, SF.P, SF.K, h, SF.avgh, b, SF.avgb, SFF, SFFScale, SFtheta, sps);} xue@1: xue@1: SF.FScaleMode=SFFScale; xue@1: // int K=SF.K, effL=ceil(SF.lp[SF.P-1])-ceil(SF.lp[0]); xue@1: // for (int k=0; k0) xue@1: { xue@1: double loga=log(Partials[m][fr].a); xue@1: loga-=loga0; xue@1: double ff=f/F; xue@1: int klm=floor(ff); xue@1: double f0=ff-klm; xue@1: double hlm=h[l][klm]*(1-f0)+h[l][klm+1]*f0; xue@1: b[l][m]=loga-hlm; xue@1: } xue@1: else b[l][m]=-100; xue@1: } xue@1: } xue@1: // for (int k=0; k0) a[l][m]=Partials[m][fr].a*ia0c; //log(Partials[m][fr].a); xue@1: else a[l][m]=0; xue@1: if (fmax0) loga[l][m]=log(Partials[m][fr].a); xue@1: else loga[l][m]=-100; xue@1: if (fmax0) loga[l][m]=log(Partials[m][fr].a); xue@1: else loga[l][m]=-100; xue@1: if (fmax0) memcpy(h[l], h[0], sizeof(double)*(K+2)); xue@1: double loga0=log(A0C[l]); xue@1: for (int m=0; m0) LogAS[m]/=ccount; xue@1: else LogAS[m]=0; xue@1: } xue@1: xue@1: DeAlloc2(loga); DeAlloc2(f); xue@1: return 0; xue@1: }//S_F_SV_cf xue@1: Chris@5: /** xue@1: function SF_FB: computes filter coefficients with filter-bank method: single frame. See "further xue@1: reading", pp.12, P5. xue@1: xue@1: In: al[][M], fl[][M]: partial amplitudes and frequencies, al[0] and fl[0] are of current frame xue@1: F: filter response sampling interval xue@1: LMode: 1: current frame is the first frame; -1: the last frame; 0: neither first nor last frame xue@1: Out: hl[K+2]: filter coefficients integrated at current frame xue@1: xue@1: Returns K. xue@1: */ xue@1: int SF_FB(double* hl, int M, int K, double** al, double** fl, double F, int LMode) xue@1: { xue@1: memset(hl, 0, sizeof(double)*(K+2)); xue@1: double* norm=new double[K+2]; memset(norm, 0, sizeof(double)*(K+2)); xue@1: for (int m=0; m0) K1=ceil(fl[-1][m]/F); else K1=floor(fl[-1][m]/F); xue@1: t0=-1; k=K1; xue@1: if (fl[-1][m]>0 && fl[0][m]>0) do xue@1: { xue@1: t1=-1+(k*F-fl[-1][m])/(fl[0][m]-fl[-1][m]); xue@1: if (t1>0) t1=0; xue@1: xue@1: if (t0==-1){a0=al[-1][m], u0=0, w0k=1-fabs(fl[-1][m]/F-k); w0k_=1-w0k;} xue@1: else{a0=al[0][m]+t0*(al[0][m]-al[-1][m]), u0=1+t0, w0k=0, w0k_=1;} xue@1: if (t1==0){a1=al[0][m], u1=1, w1k=1-fabs(fl[0][m]/F-k); w1k_=1-w1k;} xue@1: else{a1=al[0][m]+t1*(al[0][m]-al[-1][m]), u1=1+t1, w1k=1, w1k_=0;} xue@1: xue@1: hl[k]+=I3(t1-t0, w0k, u0, a0, w1k, u1, a1); xue@1: hl[k-dfsgn]+=I3(t1-t0, w0k_, u0, a0, w1k_, u1, a1); xue@1: norm[k]+=I3(t1-t0, w0k, u0, 1, w1k, u1, 1); xue@1: norm[k-dfsgn]+=I3(t1-t0, w0k_, u0, 1, w1k_, u1, 1); xue@1: xue@1: t0=t1; xue@1: k+=dfsgn; xue@1: } xue@1: while (t1<0); xue@1: } xue@1: } xue@1: xue@1: if (LMode!=-1) xue@1: { xue@1: double a0, wk, wk_, a1; xue@1: if (fl[1][m]-fl[0][m]==0) xue@1: { xue@1: int k=floor(fl[0][m]/F); xue@1: a0=al[0][m], a1=al[1][m]; xue@1: wk=1-fabs(fl[0][m]/F-k), wk_=1-wk; xue@1: double dh=(2*a0+a1)/6.0; xue@1: hl[k]+=wk*dh; //I3(1, wk, 1, a0, wk, 0, a1); xue@1: hl[k+1]+=wk_*dh;//I3(1, wk_, 1, a0, wk_, 0, a1); xue@1: norm[k]+=wk*0.5;//I3(1, wk, 1, 1, wk, 0, 1); xue@1: norm[k+1]+=wk_*0.5;//I3(1, wk_, 1, 1, wk_, 0, 1); xue@1: } xue@1: else xue@1: { xue@1: double t0, t1, a0, u0, w0k, w0k_, a1, u1, w1k, w1k_; xue@1: dfsgn=Sign(fl[1][m]-fl[0][m]); xue@1: if (dfsgn>0) K1=ceil(fl[0][m]/F); else K1=floor(fl[0][m]/F); xue@1: t0=0; k=K1; xue@1: if (fl[0][m]>0 && fl[1][m]>0) do xue@1: { xue@1: try{ xue@1: t1=(k*F-fl[0][m])/(fl[1][m]-fl[0][m]);} xue@1: catch(...){} xue@1: if (t1>1) t1=1; xue@1: xue@1: if (t0==0){a0=al[0][m], u0=1, w0k=1-fabs(fl[0][m]/F-k); w0k_=1-w0k;} xue@1: else{a0=al[0][m]+t0*(al[1][m]-al[0][m]), u0=1-t0, w0k=1, w0k_=0;} xue@1: if (t1==1){a1=al[1][m], u1=0, w1k=1-fabs(fl[1][m]/F-k); w1k_=1-w1k;} xue@1: else{a1=al[0][m]+t1*(al[1][m]-al[0][m]), u1=1-t1, w1k=0, w1k_=1;} xue@1: xue@1: hl[k]+=I3(t1-t0, w0k, u0, a0, w1k, u1, a1); xue@1: hl[k-dfsgn]+=I3(t1-t0, w0k_, u0, a0, w1k_, u1, a1); xue@1: norm[k]+=I3(t1-t0, w0k, u0, 1, w1k, u1, 1); xue@1: norm[k-dfsgn]+=I3(t1-t0, w0k_, u0, 1, w1k_, u1, 1); xue@1: xue@1: t0=t1; xue@1: k+=dfsgn; xue@1: } xue@1: while (t1<1); xue@1: } xue@1: } xue@1: } xue@1: xue@1: int mink=0; while (mink<=K+1 && norm[mink]==0) mink++; xue@1: int maxk=K+1; while (maxk>=0 && norm[maxk]==0) maxk--; xue@1: int lastk=mink, nextk=-1; xue@1: for (int k=mink; k<=maxk; k++) xue@1: { xue@1: if (k==nextk) lastk=k; xue@1: else if (norm[k]!=0) hl[k]=log(hl[k]/norm[k]), lastk=k; xue@1: else xue@1: { xue@1: if (k>nextk){nextk=k+1; while (norm[nextk]==0) nextk++; hl[nextk]=log(hl[nextk]/norm[nextk]);} xue@1: hl[k]=(hl[lastk]*(nextk-k)+hl[nextk]*(k-lastk))/(nextk-lastk); xue@1: } xue@1: } xue@1: for (int k=0; kep) xue@1: { xue@1: P_Ax(q, L, M, K, d, f, F, theta); xue@1: /*debug point: watch if hAh-bh keeps decreasing xue@1: double lastdel=Del; xue@1: hAh=P_Ax(t_Ax, L, M, K, h, f, F, theta); xue@1: bh=Inner(L, K+2, b, h); xue@1: Del=hAh-bh; xue@1: if (Del>lastdel) xue@1: {lastdel=Del;} //set breakpoint here*/ xue@1: double alpha=delta/Inner(L, K+2, d, q); xue@1: MultiAdd(L, K+2, h, h, d, alpha); xue@1: if (iter%50==0 && false){P_Ax(Ax, L, M, K, h, f, F, theta); MultiAdd(L, K+2, r, b, Ax, -1);} xue@1: else MultiAdd(L, K+2, r, r, q, -alpha); xue@1: double deltanew=Inner(L, K+2, r, r); xue@1: MultiAdd(L, K+2, d, r, d, deltanew/delta); xue@1: delta=deltanew; xue@1: iter++; xue@1: } xue@1: xue@1: DeAlloc2(b); xue@1: return K; xue@1: }//SF_SV xue@1: Chris@5: /** xue@1: function SF_SV_cf: CG method for estimation source-(constant)filter model by slow-variation criterion. xue@1: xue@1: In: a[L][M], f[L][M]: partial amplitudes and frequencies xue@1: F: filter response sampling interval xue@1: ep: convergence test threshold xue@1: maxiter: maximal number of iterates xue@1: Out: h[K+2]: filter coefficients xue@1: xue@1: Returns K. xue@1: */ xue@1: int SF_SV_cf(double* h, int L, int M, int K, double** a, double** f, double F, double ep, int maxiter) xue@1: { xue@1: double* b=new double[(K+2)*7]; xue@1: double *Ax=&b[K+2], *d=&Ax[K+2], *r=&d[K+2], *q=&r[K+2]; xue@1: xue@1: //calcualte b xue@1: P1_b_cf(b, L, M, K, a, f, F); xue@1: //calculate Ah xue@1: //double hAh= xue@1: P_Ax_cf(Ax, L, M, K, h, f, F); xue@1: xue@1: MultiAdd(K+2, r, b, Ax, -1); xue@1: Copy(K+2, d, r); xue@1: double delta=Inner(K+2, r, r); xue@1: ep=ep*delta; xue@1: xue@1: int iter=0; xue@1: while(iterep) xue@1: { xue@1: P_Ax_cf(q, L, M, K, d, f, F); xue@1: double alpha=delta/Inner(K+2, d, q); xue@1: MultiAdd(K+2, h, h, d, alpha); xue@1: if (iter%50==0 && false){P_Ax_cf(Ax, L, M, K, h, f, F); MultiAdd(K+2, r, b, Ax, -1);} xue@1: else MultiAdd(K+2, r, r, q, -alpha); xue@1: double deltanew=Inner(K+2, r, r); xue@1: MultiAdd(K+2, d, r, d, deltanew/delta); xue@1: delta=deltanew; xue@1: iter++; xue@1: } xue@1: xue@1: delete[] b; xue@1: return K; xue@1: }//SF_SV_cf xue@1: Chris@5: /** xue@1: function SF_SV_cf: CG method for estimation source-(constant)filter model by slow-variation criterion. xue@1: xue@1: In: a[L][M], f[L][M]: partial amplitudes and frequencies xue@1: F: filter response sampling interval xue@1: ep: convergence test threshold xue@1: maxiter: maximal number of iterates xue@1: Out: h[K+2]: filter coefficients xue@1: b[L][M]: source coefficients xue@1: xue@1: No reutrn value. xue@1: */ xue@1: void SF_SV_cf(double* h, double** b, int L, int M, int K, double** a, double** f, double F, double ep, int maxiter) xue@1: { xue@1: memset(h, 0, sizeof(double)*(K+2)); xue@1: SF_SV_cf(h, L, M, K, a, f, F, ep, maxiter); xue@1: for (int l=0; l0, -1 if x<0. xue@1: */ xue@1: int Sign(double x) xue@1: { xue@1: if (x==0) return 0; xue@1: else if (x>0) return 1; xue@1: else return -1; xue@1: }//Sign xue@1: Chris@5: /** xue@1: function SynthesizeSF: synthesizes a harmonic sinusoid representation from a TSF object. xue@1: xue@1: In: SF: a TSF object xue@1: sps: sampling rate ("samples per second") xue@1: Out: HS: teh synthesized HS. xue@1: xue@1: No return value. xue@1: */ xue@1: void SynthesizeSF(THS* HS, TSF* SF, double sps) xue@1: { xue@1: int t0=HS->Partials[0][0].t, s0=HS->Partials[0][0].s, L=SF->L, M=SF->M; xue@1: double *F0C=SF->F0C, *F0D=SF->F0D, *F0=SF->F0, offst=SF->offst; xue@1: double *logA0C=useA0?SF->logA0:SF->logA0C; xue@1: HS->Resize(M, L); xue@1: xue@1: atom** Partials=HS->Partials; xue@1: xue@1: for (int l=0; l0.5 || Partials[m][l].f<0) Partials[m][l].a=0; xue@1: else Partials[m][l].a=exp(logA0C[l]+SF->LogAS(m,l)+SF->LogAF(Partials[m][l].f,l)); xue@1: } xue@1: } xue@1: }//SynthesizeSF xue@1: xue@1: xue@1: xue@1: