Mercurial > hg > x
view vibrato.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 | fc19d45615d1 |
line wrap: on
line source
//--------------------------------------------------------------------------- #include <math.h> #include <mem.h> #include "vibrato.h" #include "arrayalloc.h" #include "fft.h" #include "hssf.h" #include "Matrix.h" #include "splines.h" #include "xcomplex.h" //--------------------------------------------------------------------------- //method TVo::TVo: default constructor TVo::TVo() { memset(this, 0, sizeof(TVo)); afres=8192; }//TVo //method TVo::~TVo: default destructor TVo::~TVo() { free(peakfr); delete[] lp; delete[] F0; if (fxr) DeAlloc2(fxr); if (fres) DeAlloc2(fres); if (LogASp) DeAlloc2(LogASp); }//~TVo /* method TVo::AllocateL: allocates or reallocates storage space whose size depends on L. This uses an external L value for allocation and updates L itself. */ void TVo::AllocateL(int AnL) { L=AnL; delete[] F0; F0=new double[(L+2)*4]; F0C=&F0[L+2], F0D=&F0[(L+2)*2], A0C=&F0[(L+2)*3]; }//AllocateL /* method TVo::AllocateP: allocates or reallocates storage space whose size depends on P, using the interal P. */ void TVo::AllocateP() { peakfr=(int*)realloc(peakfr, sizeof(int)*P); delete[] lp; lp=new double[(P+2)*3]; Dp=&lp[P+2]; Kp=(int*)&lp[(P+2)*2]; if (LogASp) DeAlloc2(LogASp); Allocate2(double, P, M, LogASp); }//AllocateP /* method TVo::AllocatePK: allocates or reallocates storage space whose size depends on both P and K. */ void TVo::AllocatePK() { if (fxr) DeAlloc2(fxr); Allocate2(double, P, 2*K+1, fxr); memset(fxr[0], 0, sizeof(double)*P*(2*K+1)); if (fres) DeAlloc2(fres); Allocate2(double, P, K, fres); }//AllocatePK /* method TVo::GetOldP: returns the number of "equivalent" cycles of the whole duration. Although P-1 cycles are delineated by lp[P], the parts before lp[0] and after lp[P-1] are also a part of the harmonic sinusoid being modeled and therefore should be taken into account when necessary. */ double TVo::GetOldP() { return P-1+lp[0]/(lp[1]-lp[0])+(L-lp[P-1])/(lp[P-1]-lp[P-2]); }//GetOldP /* methodTVo::LoadFromFileHandle: reads TVo object from a file stream. */ void TVo::LoadFromFileHandle(FILE* file) { fread(&M, sizeof(int), 1, file); fread(&L, sizeof(int), 1, file); fread(&P, sizeof(int), 1, file); fread(&K, sizeof(int), 1, file); fread(&h, sizeof(double), 1, file); fread(&afres, sizeof(int), 1, file); AllocateL(L); AllocateP(); AllocatePK(); fread(F0C, sizeof(double), L, file); fread(A0C, sizeof(double), L, file); fread(LogAF, sizeof(double), 4096, file); fread(peakfr, sizeof(int), P, file); fread(lp, sizeof(double), P, file); fread(Dp, sizeof(double), P, file); fread(Kp, sizeof(int), P, file); fread(fxr[0], sizeof(double), P*(2*K+1), file); fread(LogASp[0], sizeof(double), P*M, file); }//LoadFromFileHandle /* method TVo::ReAllocateL: reallocates storage space whose size depends on L, and transfer the contents. This uses an external L value for allocation but does not update L itself. */ void TVo::ReAllocateL(int newL) { double* newF0=new double[(newL+2)*4]; F0C=&newF0[newL+2], F0D=&newF0[(newL+2)*2], A0C=&newF0[(newL+2)*3]; memcpy(A0C, &F0[(L+2)*3], sizeof(double)*(L+2)); memcpy(F0D, &F0[(L+2)*2], sizeof(double)*(L+2)); memcpy(F0C, &F0[L+2], sizeof(double)*(L+2)); memcpy(newF0, F0, sizeof(double)*(L+2)); delete[] F0; F0=newF0; }//ReAllocateL /* method TVo::SaveToFile: saves a TVo object to a file. In: filename: path to the destination file. */ void TVo::SaveToFile(char* filename) { FILE* file=fopen(filename, "wb"); if (file) { SaveToFileHandle(file); fclose(file); } else { throw(strcat((char*)"Cannot open file ", filename)); } }//SaveToFile /* method TVo::SaveToFileHandle: saves a TVo object to an open file stream. */ void TVo::SaveToFileHandle(FILE* file) { fwrite(&M, sizeof(int), 1, file); fwrite(&L, sizeof(int), 1, file); fwrite(&P, sizeof(int), 1, file); fwrite(&K, sizeof(int), 1, file); fwrite(&h, sizeof(double), 1, file); fwrite(&afres, sizeof(int), 1, file); fwrite(F0C, sizeof(double), L, file); fwrite(A0C, sizeof(double), L, file); fwrite(LogAF, sizeof(double), 4096, file); fwrite(peakfr, sizeof(int), P, file); fwrite(lp, sizeof(double), P, file); fwrite(Dp, sizeof(double), P, file); fwrite(Kp, sizeof(int), P, file); fwrite(fxr[0], sizeof(double), P*(2*K+1), file); fwrite(LogASp[0], sizeof(double), P*M, file); }//SaveToFileHandle //--------------------------------------------------------------------------- //functions /* function AnalyzeV: calculates all basic and non-basic descriptors of a vibrato from a harmonic sinusoid In: HS: harmonic sinusoid to compute vibrato representation from sps: sampling rate h: hop size SFMode: specifies source-filter estimation criterion, 0=FB (filter bank), 1=SV (slow variation) SFF: filter response sampling interval SFScale: set if filter sampling uses mel scale SFtheta: balancing factor of amplitude and frequency variations, needed for SV approach Out: V: a TVo object hosting vibrato descriptors (vibrato representation) of HS cyclefrcount: number of cycles between cycle boundaries, equals V.P-1. cyclefrs[cyclefrcount], cyclefs[cyclefrcount]: time (in frames) and F0 centroid of cycles. These are knots from which V.F0C[] is interpolated. peaky[V.P]: shape score of cycle peaks No return value. */ void AnalyzeV(THS& HS, TVo& V, double*& peaky, double*& cyclefrs, double*& cyclefs, double sps, double h, int* cyclefrcount, int SFMode, double SFF, int SFFScale, double SFtheta) { int M=HS.M, Fr=HS.Fr; if (M<=0 || Fr<=0) return; atom** Partials=HS.Partials; //basic descriptor: h V.h=h; //demodulating pitch //Basic descriptor: L V.AllocateL(Fr); double* AA=new double[Fr]; //find the pitch track V.F0max=0, V.F0min=1; for (int fr=0; fr<Fr; fr++) { double suma2=0, suma2p=0; for (int m=0; m<M; m++) { double a=Partials[m][fr].a, p=Partials[m][fr].f/(m+1); if (p<=0) break; suma2+=a*a, suma2p+=a*a*p; } V.F0[fr]=suma2p/suma2; if (V.F0max<V.F0[fr]) V.F0max=V.F0[fr]; if (V.F0min>V.F0[fr]) V.F0min=V.F0[fr]; AA[fr]=suma2; } //Basic descriptor: M V.M=0.45/V.F0max; if (V.M>M) V.M=M; //rough estimation of rate double* f0d=new double[Fr-1]; for (int i=0; i<Fr-1; i++) f0d[i]=V.F0[i+1]-V.F0[i]; RateAndReg(V.rate, V.regularity, f0d, 0, Fr-2, 8, sps, h); delete[] f0d; //find peaks of the pitch track free(V.peakfr); V.peakfr=(int*)malloc(sizeof(int)*Fr/2); double periodinframe=sps/(V.rate*h); FindPeaks(V.peakfr, V.P, V.F0, Fr, periodinframe, peaky); if (V.P>=1) //de-modulation { //Basic descriptor: F0C[] DeFM(V.F0C, V.F0, AA, V.P, V.peakfr, Fr, V.F0Overall, *cyclefrcount, cyclefrs, cyclefs, true); //Basic descriptor: A0C[] DeAM(V.A0C, AA, V.P, V.peakfr, Fr); } V.F0Cmax=0; V.F0Dmax=-1; V.F0Cmin=1; V.F0Dmin=1; for (int fr=0; fr<Fr; fr++) { if (V.F0Cmax<V.F0C[fr]) V.F0Cmax=V.F0C[fr]; if (V.F0Cmin>V.F0C[fr]) V.F0Cmin=V.F0C[fr]; V.F0D[fr]=V.F0[fr]-V.F0C[fr]; } V.D=0; int cyclestart=(V.P>=2)?V.peakfr[0]:0, cycleend=(V.P>=2)?V.peakfr[V.P-1]:Fr; for (int fr=cyclestart; fr<cycleend; fr++) { double lf0d=V.F0D[fr]; if (V.F0Dmax<lf0d) V.F0Dmax=lf0d; if (V.F0Dmin>lf0d) V.F0Dmin=lf0d; V.D+=lf0d*lf0d; } V.D=sqrt(V.D/(cycleend-cyclestart)); delete[] AA; //Calculate rate and regularity //find the section used for calculating regularity and rate { int frst=0, fren=Fr-1; while (frst<fren && V.F0D[frst]*V.F0D[frst+1]>0) frst++; while (fren>frst && V.F0D[fren]*V.F0D[fren-1]>0) fren--; RateAndReg(V.rate, V.regularity, V.F0D, frst, fren, 8, sps, h); } //Basic descriptor: P //Basic descriptor: peakfr[] periodinframe=sps/(V.rate*h); FindPeaks(V.peakfr, V.P, V.F0D, Fr, periodinframe, peaky); //Basic descriptor: lp[] V.AllocateP(); for (int p=0; p<V.P; p++) { double startfr; QIE(&V.F0D[V.peakfr[p]], startfr); V.lp[p]=startfr+V.peakfr[p]; } //Basic descriptor: LogAF[] //Source-filter modeling if (SFMode==0) S_F(V.afres, V.LogAF, V.LogAS, Fr, M, Partials, V.A0C, V.lp, V.P, V.F0Overall); else S_F_SV(V.afres, V.LogAF, V.LogAS, Fr, M, Partials, V.A0C, V.lp, V.P, SFF, SFFScale, SFtheta, sps); //the alternative: find K only V.K=50; if (V.K>periodinframe/2) V.K=periodinframe/2; //single-cycle analyses //Basic descriptor: Dp[] V.AllocatePK(); for (int p=1; p<V.P; p++) { //int frst=ceil(V.lp[p-1]), freninc=floor(V.lp[p]); int frst=V.peakfr[p-1], freninc=V.peakfr[p]; V.Dp[p]=0; for (int fr=frst; fr<=freninc; fr++) V.Dp[p]+=V.F0D[fr]*V.F0D[fr]; V.Dp[p]=sqrt(V.Dp[p]/(freninc-frst+1)); double* f0e=new double[freninc-frst+1]; for (int fr=0; fr<=freninc-frst; fr++) f0e[fr]=V.F0D[frst+fr]/V.Dp[p]; V.Kp[p]=V.K; FS_QR(V.Kp[p], V.fxr[p], &f0e[0], freninc-frst, V.lp[p]-V.lp[p-1], V.lp[p-1]-frst, V.fres[p]); delete[] f0e; memset(V.LogASp[p], 0, sizeof(double)*V.M); for (int m=0; m<V.M; m++) { int ccount=0; for (int fr=frst; fr<=freninc; fr++) { double f=Partials[m][fr].f*V.afres; if (f<=0) continue; int intf=floor(f); V.LogASp[p][m]=V.LogASp[p][m]+log(Partials[m][fr].a/V.A0C[fr])-(V.LogAF[intf]*(intf+1-f)+V.LogAF[intf+1]*(f-intf)); ccount++; } if (ccount>0) V.LogASp[p][m]/=ccount; else V.LogASp[p][m]=0; } } memset(V.FXR, 0, sizeof(double)*2*V.K); memset(V.FRes, 0, sizeof(double)*V.K); double sumdp=0; for (int p=1; p<V.P; p++) sumdp+=V.Dp[p], V.FXR[0]+=V.fxr[p][0]*V.Dp[p], V.FRes[0]+=V.fres[p][0]*V.Dp[p]; V.FXR[0]/=sumdp, V.FRes[0]/=sumdp; for (int k=1; k<V.K; k++) { double sumdp=0; for (int p=1; p<V.P; p++) { if (k<V.Kp[p]) { V.FXR[2*k-1]+=V.fxr[p][2*k-1]*V.Dp[p]; V.FXR[2*k]+=V.fxr[p][2*k]*V.Dp[p]; V.FRes[k]+=V.fres[p][k]*V.Dp[p]; sumdp+=V.Dp[p]; } } V.FXR[2*k-1]/=sumdp, V.FXR[2*k]/=sumdp, V.FRes[k]/=sumdp; } }//AnalyzeV /* function copeak: measures the similarity of F0 between frst and fren to a cosine cycle 0~2pi. In: F0[peakfr[frst]:peakfr[fren]] periodinframe: period of the cosine reference, in frames Returns the correlation coefficient. */ double copeak(double* F0, int* peakfr, int frst, int fren, double periodinframe) { double ef0=0, rfs=0, rff=0, rss=0; int frcount=0; for (int fr=peakfr[frst]; fr<=peakfr[fren]; fr++) ef0+=F0[fr], frcount++; ef0/=frcount; for (int fr=peakfr[frst]; fr<=peakfr[fren]; fr++) { double s=cos(2*M_PI*(fr-peakfr[frst])/periodinframe), f=F0[fr]; rfs+=(f-ef0)*s; rff+=(f-ef0)*(f-ef0); rss+=s*s; } return rfs/sqrt(rff*rss); }//copeak /* function CorrectFS: time-shifts Fourier series so that maximum is reached at 0. This is done by finding the actual peak numerically then shifting it to 0. In: c[2K-1]: Fourier series coefficients, in the order of 0r, 1i, 1r, 2i, 2r, ..., so that the series is expanded as c[0]+c[1]sinx+c[2]cosx+c[3]sin2x+c[4]cos2x+...c[2K-2]cos(K-1)x epx: a small positive value for convergence test for finding the peak maxiter: maximal number of iterates for finding the peak Out: c[2K-1]: updated Fourier series coefficients. No return value. */ void CorrectFS(int K, double* c, double epx=1e-8, int maxiter=10) { double y=0, kb=0, kka=0, th2pi=0, dth2pi=0, my, mth2pi; epx=2*M_PI*epx; int iter=0; for (int k=1; k<K; k++) y+=c[2*k], kb+=k*c[2*k-1], kka+=k*k*c[2*k]; my=y; dth2pi=(kka>0)?(kb/kka):(kb*0.1); while (iter<maxiter && fabs(dth2pi)>epx) { iter++; th2pi+=dth2pi; kb=kka=y=0; for (int k=1; k<K; k++) { double cc=cos(k*th2pi), ss=sin(k*th2pi); y+=(c[2*k]*cc+c[2*k-1]*ss); kb+=k*(-c[2*k]*ss+c[2*k-1]*cc); kka+=k*k*(c[2*k]*cc+c[2*k-1]*ss); } if (y>my) my=y, mth2pi=th2pi; dth2pi=(kka>0)?(kb/kka):(kb*0.1); } if (iter>=maxiter || th2pi!=mth2pi) { th2pi=mth2pi; } for (int k=1; k<K; k++) { double cc=cos(k*th2pi), ss=sin(k*th2pi); double tmp=c[2*k]*cc+c[2*k-1]*ss; c[2*k-1]=-c[2*k]*ss+c[2*k-1]*cc; c[2*k]=tmp; } }//CorrectFS /* function DeAM: amplitude demodulation based on given segmentation into cycles In: A1[Fr]: original amplitude peakfr[npfr]: cycle boundaries (literally, "frame indices of frequency modulation peaks") Out: A2[Fr]: demodulated amplitude No return value. */ void DeAM(double* A2, double* A1, int npfr, int* peakfr, int Fr) { if (npfr==1) {memcpy(A2, A1, sizeof(double)*Fr); return;} double *frs=new double[npfr*2], *a=&frs[npfr]; for (int i=0; i<npfr-1; i++) { int frst=peakfr[i], fren=peakfr[i+1]; a[i]=(A1[frst]+A1[fren])*0.5; frs[i]=(frst*A1[frst]+fren*A1[fren])*0.5; for (int fr=frst+1; fr<fren; fr++) a[i]+=A1[fr], frs[i]+=fr*A1[fr]; frs[i]/=a[i]; a[i]=log(sqrt(a[i]/(fren-frst))); } if (npfr==2) { A2[0]=exp(a[0]); for (int fr=1; fr<Fr; fr++) A2[fr]=A2[0]; } else if (npfr==3) { double alp=(a[1]-a[0])/(frs[1]-frs[0]); for (int fr=0; fr<Fr; fr++) A2[fr]=exp(a[0]+(fr-frs[0])*alp); } else if (npfr==4) { double x0=frs[0], x1=frs[1], x2=frs[2], y0=log(a[0]), y1=log(a[1]), y2=log(a[2]); double ix0_12=y0/((x0-x1)*(x0-x2)), ix1_02=y1/((x1-x0)*(x1-x2)), ix2_01=y2/((x2-x0)*(x2-x1)); double aa=ix0_12+ix1_02+ix2_01, b=-(x1+x2)*ix0_12-(x0+x2)*ix1_02-(x0+x1)*ix2_01, c=x1*x2*ix0_12+x0*x2*ix1_02+x0*x1*ix2_01; for (int fr=0; fr<Fr; fr++) A2[fr]=exp(c+fr*(b+fr*aa)); } else { double *fa=new double[npfr*4], *fb=&fa[npfr], *fc=&fa[npfr*2], *fd=&fa[npfr*3]; CubicSpline(npfr-2, fa, fb, fc, fd, frs, a, 0, 1, A2, 1, 0, Fr-1); for (int fr=0; fr<Fr; fr++) A2[fr]=exp(A2[fr]); delete[] fa; } delete[] frs; }//DeAM /* function DeAM: wrapper function using floating-point cycle boundaries In: A1[Fr]: original amplitude lp[npfr]: cycle boundaries Out: A2[Fr]: demodulated amplitude No return value. */ void DeAM(double* A2, double* A1, int npfr, double* lp, int Fr) { int* peakfr=new int[npfr]; for (int i=0; i<npfr; i++) peakfr[i]=ceil(lp[i]); DeAM(A2, A1, npfr, peakfr, Fr); delete[] peakfr; }//DeAM /* function DeFM: frequency demodulation based on given segmentation into cycles In: f1[Fr], AA[Fr]: original frequency and partial-independent amplitude peakfr[npfr]: cycle boundaries (literally, "frame indices of frequency modulation peaks") furthursmoothing: specifies if a second round demodulation is to be performed for more smooth carrier Out: f2[Fr]: demodulated frequency f[fcount], frs[fcount]: frequency and time (in frames) of carrier knots, optional fct: frequency centroid No return value. */ void DeFM(double* f2, double* f1, double* AA, int npfr, int* peakfr, int Fr, double& fct, int& fcount, double* &frs, double* &f, bool furthersmoothing) { double ac=0; fct=0; if (npfr==1) { memcpy(f2, f1, sizeof(double)*Fr); for (int fr=0; fr<Fr; fr++) ac+=AA[fr], fct+=f1[fr]*AA[fr]; fct/=ac; return; } bool localfrs=(frs==(double*)0xFFFFFFFF), localf=(f==(double*)0xFFFFFFFF); if (!localfrs) delete[] frs; if (!localf) delete[] f; frs=new double[npfr]; f=new double[npfr]; for (int i=0; i<npfr-1; i++) { int frst=peakfr[i], fren=peakfr[i+1]; f[i]=(f1[frst]*AA[frst]+f1[fren]*AA[fren])*0.5; frs[i]=(frst*AA[frst]+fren*AA[fren])*0.5; double lrec=(AA[frst]+AA[fren])*0.5; for (int fr=frst+1; fr<fren; fr++) f[i]+=f1[fr]*AA[fr], frs[i]+=fr*AA[fr], lrec+=AA[fr]; ac+=lrec; fct+=f[i]; f[i]/=lrec, frs[i]/=lrec; } fct/=ac; if (furthersmoothing) { //further smoothing int newnpfr=1; for (int pfr=1; pfr<npfr-2; pfr++) { if ((f[pfr]>f[pfr-1] && f[pfr]>f[pfr+1]) || (f[pfr]<f[pfr-1] && f[pfr]<f[pfr+1])) { //this is a peak or valley if ((pfr+1<npfr-2 && f[pfr+1]>f[pfr] && f[pfr+1]>f[pfr+2]) || (f[pfr+1]<f[pfr] && f[pfr+1]<f[pfr+2])) { frs[newnpfr]=0.5*(frs[pfr]+frs[pfr+1]), f[newnpfr]=0.5*(f[pfr]+f[pfr+1]); newnpfr++; } } else { frs[newnpfr]=frs[pfr], f[newnpfr]=f[pfr]; newnpfr++; } } frs[newnpfr]=frs[npfr-2], f[newnpfr]=f[npfr-2]; newnpfr++; newnpfr++; npfr=newnpfr; } Smooth_Interpolate(f2, Fr, npfr, f, frs); fcount=npfr-1; if (localfrs) delete[] frs; if (localf) delete[] f; }//DeFM /* function DeFM: wrapper function using floating-point cycle boundaries In: f1[Fr], AA[Fr]: original frequency and partial-independent amplitude lp[npfr]: cycle boundaries furthursmoothing: specifies if a second round demodulation is to be performed for more smooth carrier Out: f2[Fr]: demodulated frequency f[fcount], frs[fcount]: frequency and time (in frames) of carrier knots, optional fct: frequency centroid No return value. */ void DeFM(double* f2, double* f1, double* AA, int npfr, double* lp, int Fr, double& fct, int& fcount, double* &frs, double* &f, bool furthersmoothing) { int* peakfr=new int[npfr]; for (int i=0; i<npfr; i++) peakfr[i]=ceil(lp[i]); DeFM(f2, f1, AA, npfr, peakfr, Fr, fct, fcount, frs, f, furthersmoothing); delete[] peakfr; }//DeFM /* function FindPeaks: find modulation peaks of signal F0[] roughly periodical at $periodinframe In: F0[Fr]: modulated signal periodinframe: reference modulation period Out: npfr, peakfr[npfr]: modulation peaks peaky[npfr]: shape score for the peaks measuring their similarity to cosine peak, optional No return value. */ void FindPeaks(int* peakfr, int& npfr, double* F0, int Fr, double periodinframe, double*& peaky) { npfr=0; for (int fr=1; fr<Fr-1; fr++) { if (F0[fr]>F0[fr-1] && F0[fr]>F0[fr+1]) { peakfr[npfr++]=fr; } } bool localpeaky=(peaky==(double*)0xFFFFFFFF); if (!localpeaky) delete[] peaky; peaky=new double[npfr]; for (int pfr=0; pfr<npfr; pfr++) { double rfs=0, rff=0, rss=0; if (peakfr[pfr]>periodinframe/2) { double ef0=0; int frcount=0; for (int fr=peakfr[pfr]-periodinframe/2; fr<peakfr[pfr]; fr++) ef0+=F0[fr], frcount++; ef0/=frcount; for (int fr=peakfr[pfr]-periodinframe/2; fr<peakfr[pfr]; fr++) { double s=cos(2*M_PI*(fr-peakfr[pfr])/periodinframe), f=F0[fr]; rfs+=(f-ef0)*s; rff+=(f-ef0)*(f-ef0); rss+=s*s; } } if (peakfr[pfr]<Fr-periodinframe/2) { double ef0=0; int frcount=0; for (int fr=peakfr[pfr]; fr<peakfr[pfr]+periodinframe/2; fr++) ef0+=F0[fr], frcount++; ef0/=frcount; for (int fr=peakfr[pfr]; fr<peakfr[pfr]+periodinframe/2; fr++) { double s=cos(2*M_PI*(fr-peakfr[pfr])/periodinframe), f=F0[fr]; rfs+=(f-ef0)*s; rff+=(f-ef0)*(f-ef0); rss+=s*s; } } peaky[pfr]=rfs/sqrt(rff*rss); } int pst=0; for (int pfr=1; pfr<npfr; pfr++) if (peaky[pst]<peaky[pfr]) pst=pfr; // return; //* int pen=pst+1, pfr=pst+1; while (pfr<npfr) { int impfr=-1; while (pfr<npfr && peakfr[pfr]<peakfr[pen-1]+periodinframe*0.5) pfr++; if (pfr<npfr && peakfr[pfr]<peakfr[pen-1]+periodinframe*1.5) { double mpfr=peaky[pfr]+copeak(F0, peakfr, pen-1, pfr, periodinframe); impfr=pfr; pfr++; while (pfr<npfr && peakfr[pfr]<peakfr[pen-1]+periodinframe*1.5) { double mp=peaky[pfr]+copeak(F0, peakfr, pen-1, pfr, periodinframe); if (mp>mpfr) impfr=pfr, mpfr=mp; pfr++; } } else { while (pfr<npfr) { if (peaky[pfr]>0) {impfr=pfr; break;} pfr++; } } if (impfr>=0) peakfr[pen++]=peakfr[impfr]; } pst--; pfr=pst; while (pfr>=0) { int impfr=-1; while (pfr>=0 && peakfr[pfr]>peakfr[pst+1]-periodinframe*0.5) pfr--; if (pfr>=0 && peakfr[pfr]>=peakfr[pst+1]-periodinframe*1.5) { double mpfr=peaky[pfr]+copeak(F0, peakfr, pfr, pst+1, periodinframe); impfr=pfr; pfr--; while (pfr>=0 && peakfr[pfr]>=peakfr[pst+1]-periodinframe*1.5) { double mp=peaky[pfr]+copeak(F0, peakfr, pfr, pst+1, periodinframe); if (mp>mpfr) impfr=pfr, mpfr=mp; pfr--; } } else { while (pfr>=0) { if (peaky[pfr]>0) {impfr=pfr; break;} pfr--; } } if (impfr>=0) peakfr[pst--]=peakfr[impfr]; } pst++; npfr=pen-pst; memmove(peakfr, &peakfr[pst], sizeof(int)*npfr); //*/ if (localpeaky) delete[] peaky; }//FindPeaks /* function FS: Fourier series decomposition In: data[frst:fren]: signal to decompose period: period of Fourier series decomposition shift: amount of original shift of Fourier components (from frst to frst-shift) K: number of Fourier components requested Out: K: number of Fourier components returned FXR[K], FXI[K]: real and imaginary parts of Fourier series coefficients FRES[K]: decomposition residues No return value. */ void FS(int& K, double* FXR, double* FXI, double* FRES, double* data, int frst, int fren, double period, double shift) { if (K>period/2) K=period/2; int len=fren-frst+1; double omg0=2*M_PI/period, ilen=1.0/len; //for (int fr=frst; fr<=fren; fr++) data[fr]=cos(2*M_PI*fr/period+1); double* res=new double[len]; memcpy(res, &data[frst], sizeof(double)*len); double* rec=new double[len]; double resene=0; for (int i=0; i<len; i++) resene+=res[i]*res[i]; double ene=resene; for (int k=0; k<K; k++) { // double eer=0, eei=0; double xr=0, xi=0, omg=k*omg0; for (int fr=frst; fr<=fren; fr++) { double ph=omg*(fr-shift); double c=cos(ph), s=sin(ph); xr+=data[fr]*c, xi+=data[fr]*s; // eer+=c*c, eei+=s*s; } xr*=ilen, xi*=ilen; // if (eer>0) xr/=eer; // if (eei>0) xi/=eei; FXR[k]=xr, FXI[k]=xi; double lresene=0; for (int fr=frst; fr<=fren; fr++) { double ph=omg*(fr-shift); // rec[fr-frst]=xr*cos(ph)+xi*sin(ph); if (k==0) rec[fr-frst]=xr*cos(ph)+xi*sin(ph); else rec[fr-frst]=2*(xr*cos(ph)+xi*sin(ph)); res[fr-frst]-=rec[fr-frst]; lresene+=res[fr-frst]*res[fr-frst]; } resene=lresene; FRES[k]=resene/ene; } delete[] rec; delete[] res; }//FS /* function FS_QR: Fourier series decomposition with QR orthogonalization. Since the Fourier series is applied on finite-length discrate signal, the Fourier components are no longer orthogonal to each other. A decreasing residue can be guaranteed by applying QR (or any other) orthogonalization process to the Fourier components before decomposition. In: data[0:Fr]: signal to decompose period: period of Fourier series decomposition shift: amount of original shift of Fourier components (from 0 to -shift) K: number of Fourier components requested Out: K: number of Fourier components returned FXR[2K-1]: Fourier series coefficients, in the order of 0r, 1i, 1r, 2i, 2r, .... FRES[K]: decomposition residues, optional No return value. */ void FS_QR(int& K, double* FXR, double* data, int Fr, double period, double shift, double* FRES) { int len=Fr+1; if (K>period/2) K=period/2; if (K>Fr/2) K=Fr/2; if (K>len/2) K=len/2; if (K<=0) return; memset(FXR, 0, sizeof(double)*(2*K-1)); double omg0=2*M_PI/period, ene, resene; if (FRES) { ene=0; for (int i=0; i<len; i++) ene+=data[i]*data[i]; resene=ene; } /*debug only double *res=new double[len*4], *rec=&res[len]; memcpy(res, data, sizeof(double)*len); memset(rec, 0, sizeof(double)*len); double resene2=resene;//*/ int NK=K*2-1; Alloc2(len, NK, A); Alloc2(len, len, Q); Alloc2(len, NK, R); for (int fr=0; fr<=Fr; fr++) A[fr][0]=1; for (int k=1; k<(NK+1)/2; k++) { double omg=k*omg0; for (int fr=0; fr<=Fr; fr++){double ph=omg*(fr-shift); A[fr][2*k-1]=2*sin(ph), A[fr][2*k]=2*cos(ph);} } QR_householder(len, NK, A, Q, R);/////////////////// GIUT(NK, R); for (int k=0; k<NK; k++) { double xr=0; for (int fr=0; fr<=Fr; fr++) { double c=Q[fr][k]; xr+=data[fr]*c; } for (int kk=0; kk<=k; kk++) FXR[kk]+=xr*R[kk][k]; /*debug only double lresene=0; for (int fr=0; fr<=Fr; fr++) { rec[fr]=0; for (int kk=0; kk<=k; kk++) rec[fr]+=FXR[kk]*A[fr][kk]; res[fr]=data[fr]-rec[fr]; lresene+=res[fr]*res[fr]; } resene2=lresene; */ if (FRES) { resene-=xr*xr; if (k%2==0) FRES[k/2]=resene/ene; } } /* debug only delete[] res; //*/ DeAlloc2(A); DeAlloc2(Q); DeAlloc2(R); }//FS_QR /* function InterpolateV: adjusts modulation rate to $rate times the current value. Since TVo is based on individual cycles, this operation involves finding new cycle boundaries and recomputing other single- cycle descriptors by interpolation. This is used for time stretching and cycle rate adjustment. In: V: a TVo object to adjust newP: number of total cycles after adjustment. rate: amount of adjustment. Out: another TVo object with new cycle boundaries and single-cycle descriptors interpoated from V Returns pointer to the output TVo. This function does not affect the content in V. */ TVo* InterpolateV(double newP, double rate, TVo& V) { double Pst=-V.lp[0]/(V.lp[1]-V.lp[0]); double oldP=V.P-1+(V.L-V.lp[V.P-1])/(V.lp[V.P-1]-V.lp[V.P-2])-Pst; TVo* newV=new TVo; memcpy(newV, &V, sizeof(TVo)); newV->F0C=0; newV->A0C=0; newV->peakfr=0; newV->Dp=0; newV->lp=0, newV->Kp=0; newV->fxr=0; newV->LogASp=0; newV->F0=0; newV->F0D=0; newV->fres=0; int inewP=ceil(newP+Pst); newV->P=inewP; newV->peakfr=new int[inewP]; newV->AllocateP(); newV->AllocatePK(); newV->lp[0]=V.lp[0]/rate; newV->peakfr[0]=floor(newV->lp[0]+0.5); for (int p=1; p<inewP; p++) { double rp=1+(p-1)*(oldP-2+Pst)/(newP-2+Pst); int ip=floor(rp); rp=rp-ip; if (ip+1>=V.P) ip=V.P-1, rp=0; if (fabs(rp)<1e-16) { newV->lp[p]=newV->lp[p-1]+(V.lp[ip]-V.lp[ip-1])/rate; newV->Dp[p]=V.Dp[ip]; newV->Kp[p]=V.Kp[ip]; memcpy(newV->fxr[p], V.fxr[ip], sizeof(double)*2*newV->Kp[p]); memcpy(newV->LogASp[p], V.LogASp[ip], sizeof(double)*V.M); } else { double fv1=1.0/(V.lp[ip]-V.lp[ip-1]), fv2=1.0/(V.lp[ip+1]-V.lp[ip]); double fv=rate*(fv1*(1-rp)+fv2*rp); newV->lp[p]=newV->lp[p-1]+1.0/fv; newV->Dp[p]=V.Dp[ip]*(1-rp)+V.Dp[ip+1]*rp; int minK=V.Kp[ip]; if (minK>V.Kp[ip+1]) minK=V.Kp[ip+1]; for (int k=0; k<2*minK-1; k++) newV->fxr[p][k]=V.fxr[ip][k]*(1-rp)+V.fxr[ip+1][k]*rp; for (int m=0; m<V.M; m++) newV->LogASp[p][m]=V.LogASp[ip][m]*(1-rp)+V.LogASp[ip+1][m]*rp; newV->Kp[p]=minK; } newV->peakfr[p]=floor(newV->lp[p]+0.5); memset(newV->fres[0], 0, sizeof(double)*newV->P*V.K); } int newL=newV->lp[inewP-1]+(newP+Pst-(inewP-1))*(V.lp[V.P-1]-V.lp[V.P-2])/rate+0.5; newV->AllocateL(newL); //F0C and A0C if (V.L!=newL) { for (int l=0; l<newL; l++) { double rl=1.0*l*(V.L-1)/(newL-1); int il=floor(rl); rl-=il; newV->F0C[l]=V.F0C[il]*(1-rl)+V.F0C[il+1]*rl; newV->A0C[l]=V.A0C[il]*(1-rl)+V.A0C[il+1]*rl; } } else { memcpy(newV->F0C, V.F0C, sizeof(double)*V.L); memcpy(newV->A0C, V.A0C, sizeof(double)*V.L); // memcpy(newV->F0, V.F0, sizeof(double)*V.L); // memcpy(newV->F0D, V.F0D, sizeof(double)*V.L); } return newV; }//InterpoalteV //vibrato rate boundaries, in Hz #define MAXMOD 15.0 #define MINMOD 3.0 /* function RateAndReg: evaluates modulation rate and regularity In: data[frst:fren]: modulated signal, time measured in frames padrate: padding rate used for inverse FFT sps: sampling frequency offst: hop size Out: rate, regularity: rate and regularity No return value. */ void RateAndReg(double& rate, double& regularity, double* data, int frst, int fren, int padrate, double sps, double offst) { rate=0; regularity=0; //find the section used for calculating regularity and rate int frlen=fren-frst+1, frlenp=1<<(int(log2(fren))+2), frlenpp=frlenp*padrate; double *lf=new double[frlenpp*4]; cdouble *w=(cdouble*)&lf[frlenpp]; cdouble *x=(cdouble*)&lf[frlenpp*2]; SetTwiddleFactors(frlenp, w); memset(lf, 0, sizeof(double)*frlenp); memcpy(lf, &data[frst], sizeof(double)*frlen); // for (int i=0; i<frlen; i++) lf[i]=data[frst+i]-edata; double* rdata=new double[50]; for (int i=0; i<50; i++) { rdata[i]=0; for (int j=0; j<fren-i; j++) rdata[i]+=data[j]*data[j+i]; } RFFTC(lf, NULL, NULL, log2(frlenp), w, x, 0); // xr[0]=0; for (int i=0; i<frlenp/2; i++) {x[i].x=x[i].x*x[i].x+x[i].y*x[i].y; x[i].y=0;} memset(&x[frlenp/2], 0, sizeof(cdouble)*(frlenpp-frlenp/2)); SetTwiddleFactors(frlenpp, w); CIFFTR(x, log2(frlenpp), w, lf); delete[] rdata; double minpeak=sps/(offst*MAXMOD), maxpeak=sps/(offst*MINMOD); //find 2nd highest peak at interval padrate int imaxlf=padrate*minpeak; while (imaxlf<frlenpp && imaxlf<padrate*maxpeak && lf[imaxlf]<=lf[imaxlf-padrate]) imaxlf+=padrate; double maxlf=lf[imaxlf]; for (int i=imaxlf/padrate; i<frlen/2; i++) if (maxlf<lf[i*padrate]) maxlf=lf[i*padrate], imaxlf=i*padrate; //locate the peak at interval 1 int ii=imaxlf; for (int i=ii-padrate+1; i<ii+padrate; i++) if (maxlf<lf[i]) maxlf=lf[i], imaxlf=i; double a_=0.5*(lf[imaxlf-1]+lf[imaxlf+1])-maxlf, b_=0.5*(lf[imaxlf+1]-lf[imaxlf-1]); double period=imaxlf-0.5*b_/a_; period=period/padrate; //period in frames rate=sps/(period*offst); //rate in hz regularity=(maxlf-0.25*b_*b_/a_)/lf[0]*(fren-frst)/(fren-frst-period); delete[] lf; }//RateAndReg /* function RegularizeV: synthesize a regular vibrato from the basic descriptors. In: V: a TVo object hosting vibrato descriptors sps: sampling rate h: hop size Out: HS: a harmonic sinusoid No return value. */ void RegularizeV(THS& HS, TVo& V, double sps, double h) { int K=V.Kp[1]; for (int p=2; p<V.P; p++) if (K>V.Kp[p]) K=V.Kp[p]; double D=0, *fxr=new double[2*K-1]; memset(fxr, 0, sizeof(double)*(2*K-1)); for (int p=1; p<V.P; p++) { D+=V.Dp[p]; for (int k=0; k<2*K-1; k++) fxr[k]+=V.fxr[p][k]*V.Dp[p]; } //uncomment the following line if re-normalization needed //double alfa=fxr[0]*fxr[0]; for (int k=1; k<2*K-1; k++) alfa+=2*fxr[k]*fxr[k]; alfa=sqrt(alfa); D=alfa; for (int k=0; k<2*K-1; k++) fxr[k]/=D; D/=(V.P-1); V.D=D; atom** Partials=HS.Partials; for (int l=0; l<V.L; l++) { double theta=V.rate*l*V.h/sps;//-0.25; //f0(theta) double f0=fxr[0]; for (int k=1; k<K; k++) f0=f0+2*(fxr[2*k-1]*sin(2*M_PI*k*theta)+fxr[2*k]*cos(2*M_PI*k*theta)); V.F0D[l]=D*f0; V.F0[l]=V.F0C[l]+V.F0D[l]; for (int m=0; m<V.M; m++) { if (Partials[m][l].t<0) Partials[m][l].t=Partials[0][l].t; Partials[m][l].f=(m+1)*V.F0[l]; if (Partials[m][l].f>0.5 || Partials[m][l].f<0) Partials[m][l].f=-1, Partials[m][l].a=0; else Partials[m][l].a=V.A0C[l]*exp(V.LogAS[m]+V.LogAF[int(Partials[m][l].f*V.afres)]); } } delete[] fxr; }//RegularizeV /* function QIE: computes extremum using quadratic interpolation In: y[-1:1]: three points to interpolate from. It is assumed y[0] is larger (or smaller) than both y[-1] and y[1]. Returns the extremum of y. */ double QIE(double* y) { double a=0.5*(y[1]+y[-1])-y[0], b=0.5*(y[1]-y[-1]); return y[0]-0.25*b*b/a; }//QIE /* function QIE: computes extremum using quadratic interpolation In: y[-1:1]: three points to interpolate from. It is assumed y[0] is larger (or smaller) than both y[-1] and y[1]. Out: x: the argument value that yields extremum of y(x) Returns the extremum of y. */ double QIE(double* y, double& x) { double a=0.5*(y[1]+y[-1])-y[0], b=0.5*(y[1]-y[-1]); x=-0.5*b/a; return y[0]-0.25*b*b/a; }//QIE /* function S_F: original source-filter estimation used in AES124. In: afres: filter response resolution Partials[M][Fr]: HS partials A0C[Fr]: partial-independent amplitude carrier lp[P]: cycle boundaries F0Overall: average fundamental frequency Out: LogAF[afres/2]: filter response LogAS[M]: source amplitudes Returns 0. */ double S_F(int afres, double* LogAF, double* LogAS, int Fr, int M, atom** Partials, double* A0C, double* lp, int P, double F0Overall) { //SOURCE-FILTER estimation routines //derivative of log A(f), f is sampled at 1/8192 (5hz), averaged over (-15hz, 15hz) double *DAF=new double[afres], *NAF=&DAF[afres/2]; memset(DAF, 0, sizeof(double)*afres); double avgwidth1, avgwidth2; for (int fr=lp[1]; fr<lp[P-1]; fr++) for (int m=0; m<M; m++) { if (Partials[m][fr].f>0 && Partials[m][fr-1].f>0 && Partials[m][fr+1].f>0) { double f_1=Partials[m][fr-1].f, f0=Partials[m][fr].f, f1=Partials[m][fr+1].f, a_1=Partials[m][fr-1].a/A0C[fr-1], a1=Partials[m][fr+1].a/A0C[fr+1]; if ((f0-f_1)*(f0-f1)<0) { double dlogaf_df=(log(a1)-log(a_1))/(f1-f_1); //calculate derivative of log //this derivative contributes within a frequency interval of |f1-f_1| if (f1<f_1) {double tmp=f1; f1=f_1; f_1=tmp;} int startbin=ceil(f_1*afres), endbin=floor(f1*afres); if (startbin<0) startbin=0; avgwidth1=(f0-f_1)*afres, avgwidth2=(f1-f0)*afres; for (int i=startbin; i<=endbin; i++) { double fi=i-f0*afres, w; if (fi<0) w=1-fabs(fi)/avgwidth1; else w=1-fabs(fi)/avgwidth2; DAF[i]+=dlogaf_df*w, NAF[i]+=w; } } } } for (int i=0; i<afres/2; i++) if (NAF[i]>0) DAF[i]=DAF[i]/NAF[i]; //else NAF[i]=0; int i=0, nbands=0, bandsstart[100], bandsendinc[100]; double mininaf=3; while (i<afres/2) { while (i<afres/2 && NAF[i]<mininaf) i++; if (i>=afres/2) break; bandsstart[nbands]=i; while (i<afres/2 && NAF[i]>0) i++; if (i>=afres/2) {bandsendinc[nbands++]=i-1; break;} if (NAF[i]<=0) while (NAF[i]<mininaf) i--; bandsendinc[nbands++]=i++; } //integrate DAF over the fundamental band, with AF(F0Overall)=1 i=F0Overall*afres; double theta=F0Overall*afres-i; LogAF[i]=-0.5*theta*(DAF[i]+DAF[i]*(1-theta)+DAF[i+1]*theta)/afres; i--; while (i>=bandsstart[0]){LogAF[i]=LogAF[i+1]-0.5*(DAF[i]+DAF[i+1])/afres; i--;} i=F0Overall*afres+1; LogAF[i]=0.5*(1-theta)*(DAF[i]+DAF[i-1]*(1-theta)+DAF[i]*theta)/afres; i++; while (i<=bandsendinc[0]){LogAF[i]=LogAF[i-1]+0.5*(DAF[i]+DAF[i-1])/afres; i++;} int band=1; while (band<nbands) { //integrate DAF over band-th band, first ignore the blank band LogAF[bandsstart[band]]=LogAF[bandsendinc[band-1]]; for (int i=bandsstart[band]+1; i<=bandsendinc[band]; i++) LogAF[i]=LogAF[i-1]+0.5*(DAF[i]+DAF[i-1])/afres; //then look for the shift required between bands double cshift=0; int ccount=0; for (int fr=lp[1]; fr<lp[P-1]; fr++) { double f=Partials[band-1][fr].f*afres; if (bandsendinc[band-1]>bandsstart[band-1] && (f<bandsstart[band-1] || f>bandsendinc[band-1])) continue; int intf=floor(f); double logaflast=LogAF[intf]+(DAF[intf]+0.5*(DAF[intf+1]-DAF[intf])*(f-intf))*(f-intf)/afres; f=Partials[band][fr].f*afres; if (bandsendinc[band]>bandsstart[band] && (f<bandsstart[band] || f>bandsendinc[band])) continue; intf=floor(f); double logafthis=LogAF[intf]+(DAF[intf]+0.5*(DAF[intf+1]-DAF[intf])*(f-intf))*(f-intf)/afres; cshift=cshift+log(Partials[band][fr].a*(band+1)/(Partials[band-1][fr].a*band))+logaflast-logafthis; ccount++; } cshift/=ccount; //apply the shift for (int i=bandsstart[band]; i<=bandsendinc[band]; i++) LogAF[i]+=cshift; //make up the blank band int lastend=bandsendinc[band-1], thisstart=bandsstart[band]; for (int i=lastend+1; i<thisstart; i++) LogAF[i]=LogAF[lastend]+cshift*(i-lastend)/(thisstart-lastend); band++; } delete[] DAF; int tmpband=bandsstart[0]; for (int i=0; i<tmpband; i++) LogAF[i]=LogAF[tmpband]; tmpband=bandsendinc[nbands-1]; for (int i=tmpband; i<afres/2; i++) LogAF[i]=LogAF[tmpband]; //Here LogAF contains the filter model, new get the source model memset(LogAS, 0, sizeof(double)*100); for (int m=0; m<M; m++) { int ccount=0; for (int fr=lp[1]; fr<lp[P-1]; fr++) { double f=Partials[m][fr].f*afres; if (f<=0) continue; int intf=floor(f); LogAS[m]=LogAS[m]+log(Partials[m][fr].a/A0C[fr])-(LogAF[intf]*(intf+1-f)+LogAF[intf+1]*(f-intf)); ccount++; } if (ccount>0) LogAS[m]/=ccount; else LogAS[m]=0; } return 0; }//S_F /* function S_F_SV: slow-variation source-filter estimation used in AES126, adapted from TSF to TVo. In: afres: filter response resolution Partials[M][Fr]: HS partials A0C[Fr]: partial-independent amplitude carrier lp[P]: cycle boundaries F: filter response sampling interval FScaleMode: set if filter sampling uses mel scale theta: balancing factor of amplitude and frequency variations, needed for SV approach Out: LogAF[afres/2]: filter response LogAS[M]: source amplitudes Returns 0. */ double S_F_SV(int afres, double* LogAF, double* LogAS, int Fr, int M, atom** Partials, double* A0C, double* lp, int P, double F, int FScaleMode, double theta, double Fs) { int lp0=lp[1], lpp=lp[P-1]; int L=lpp-lp0; Alloc2(L, M, loga); Alloc2(L, M, f); double fmax=0; for (int l=0; l<L; l++) { int fr=lp0+l; for (int m=0; m<M; m++) { f[l][m]=Partials[m][fr].f; if (FScaleMode) f[l][m]=log(1+f[l][m]*Fs/700)/log(1+Fs/700); if (f[l][m]>0) loga[l][m]=log(Partials[m][fr].a); else loga[l][m]=-100; if (fmax<f[l][m]) fmax=f[l][m]; } } int K=floor(fmax/F); Alloc2(L, K+2, h); memset(h[0], 0, sizeof(double)*L*(K+2)); SF_SV(h, L, M, K, loga, f, F, theta, 1e-6, L*(K+2)); for (int k=0; k<K+2; k++) { for (int l=1; l<L; l++) h[0][k]+=h[l][k]; h[0][k]/=L; } for (int i=0; i<afres/2; i++) { double freq=i*1.0/afres; int k=floor(freq/F); double f_plus=freq/F-k; if (k<K+1) LogAF[i]=h[0][k]*(1-f_plus)+h[0][k+1]*f_plus; else LogAF[i]=h[0][K+1]; } memset(LogAS, 0, sizeof(double)*100); for (int m=0; m<M; m++) { int ccount=0; for (int fr=lp[1]; fr<lp[P-1]; fr++) { double f=Partials[m][fr].f*afres; if (f<=0) continue; int intf=floor(f); LogAS[m]=LogAS[m]+log(Partials[m][fr].a/A0C[fr])-(LogAF[intf]*(intf+1-f)+LogAF[intf+1]*(f-intf)); ccount++; } if (ccount>0) LogAS[m]/=ccount; else LogAS[m]=0; } DeAlloc2(loga); DeAlloc2(f); DeAlloc2(h); return 0; }//S_F_SV /* function SynthesizeV: synthesizes a harmonic sinusoid from vibrato descriptors In: V: a TVo object hosting vibrato descriptors sps: sampling rate UseK: maximal number of Fourier series components to use to construct frequency modulator Out: HS: a harmonic sinusoid No return value. */ void SynthesizeV(THS* HS, TVo* V, double sps, int UseK) { int HSt0=HS->Partials[0][0].t, HSs0=HS->Partials[0][0].s, L=V->L, M=V->M, P=V->P, *Kp=V->Kp, K=V->K, afres=V->afres; double **fxr=V->fxr, *lp=V->lp, **LogASp=V->LogASp, *LogAF=V->LogAF, *Dp=V->Dp, *F0C=V->F0C, *F0D=V->F0D, *F0=V->F0, *A0C=V->A0C, h=V->h; HS->Resize(M, L); double *gamp=new double[4*P], *gamm=&gamp[P]; Alloc2(P, K*2, newfxr); int* newKp=new int[P]; for (int p=1; p<P; p++) { memcpy(newfxr[p], fxr[p], sizeof(double)*2*K); newKp[p]=Kp[p]; if (UseK>=2 && newKp[p]>UseK) newKp[p]=UseK; CorrectFS(newKp[p], newfxr[p]); } double f0, f1; for (int p=1; p<P-1; p++) { if (p==1) { f0=newfxr[p][0]; for (int k=1; k<newKp[p]; k++) f0=f0+2*newfxr[p][2*k]; } else f0=f1; f1=newfxr[p+1][0]; for (int k=1; k<newKp[p+1]; k++) f1=f1+2*newfxr[p+1][2*k]; gamp[p]=(Dp[p+1]*f1-Dp[p]*f0)/2; gamm[p+1]=-gamp[p]; //additive correction } gamm[1]=-gamp[1], gamp[P-1]=-gamm[P-1]; //additive correction atom** Partials=HS->Partials; for (int p=0; p<P; p++) { double l0, lrange; int lst, len, ilp; if (p==0) lst=0, len=ceil(lp[0]), ilp=1; else if (p==P-1) lst=ceil(lp[p-1]), len=L, ilp=p-1; else lst=ceil(lp[p-1]), len=ceil(lp[p]), ilp=p; l0=lp[ilp-1], lrange=lp[ilp]-l0; for (int l=lst; l<len; l++) { Partials[0][l].s=HSs0; Partials[0][l].t=HSt0+h*l; double theta=(l-l0)/lrange; double f0=newfxr[ilp][0]; for (int k=1; k<newKp[ilp]-1; k++) f0=f0+2*(newfxr[ilp][2*k-1]*sin(2*M_PI*k*theta)+newfxr[ilp][2*k]*cos(2*M_PI*k*theta)); F0D[l]=f0*Dp[ilp]+gamm[ilp]*(1-theta)+gamp[ilp]*theta; //additive correction // V.F0D[l]=f0*V.Dp[lp]; //no correction F0[l]=F0C[l]+F0D[l]; for (int m=0; m<M; m++) { Partials[m][l].s=HSs0; Partials[m][l].t=Partials[0][l].t; Partials[m][l].f=(m+1)*F0[l]; if (Partials[m][l].f>0.5 || Partials[m][l].f<0) Partials[m][l].a=0; else if (ilp==1) Partials[m][l].a=A0C[l]*exp(LogASp[1][m]*(1-0.5*theta)+LogASp[2][m]*0.5*theta+LogAF[int(Partials[m][l].f*afres)]); else if (ilp==P-1) Partials[m][l].a=A0C[l]*exp(LogASp[ilp][m]*0.5*(1+theta)+LogASp[ilp-1][m]*0.5*(1-theta)+LogAF[int(Partials[m][l].f*afres)]); else // Partials[m][l].a=A0C[l]*exp(LogASp[ilp][m]*0.5+LogASp[ilp-1][m]*0.5*(1-theta)+LogASp[ilp+1][m]*0.5*theta+LogAF[int(Partials[m][l].f*afres)]); Partials[m][l].a=A0C[l]*exp(LogASp[p][m]+LogAF[int(Partials[m][l].f*afres)]); } } } delete[] gamp; DeAlloc2(newfxr); delete[] newKp; // VibratoDemoForm->Label13->Caption=L; }//SynthesizeV