diff SinEst.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
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SinEst.cpp	Tue Oct 05 10:45:57 2010 +0100
@@ -0,0 +1,3970 @@
+//---------------------------------------------------------------------------
+
+#include <stddef.h>
+#include "SinEst.h"
+#include "fft.h"
+#include "opt.h"
+#include "SinSyn.h"
+#include "splines.h"
+#include "WindowFunctions.h"
+
+//---------------------------------------------------------------------------
+/*
+  function dsincd_unn: derivative of unnormalized discrete sinc function
+
+  In: x, scale N
+
+  Returns the derivative of sincd_unn(x, N)
+*/
+double dsincd_unn(double x, int N)
+{
+  double r=0;
+  double omg=M_PI*x;
+  double domg=omg/N;
+  if (fabs(x)>1e-6)
+  {
+    r=M_PI*(cos(omg)-sin(omg)*cos(domg)/sin(domg)/N)/sin(domg);
+  }
+  else
+  {
+    if (domg!=0)
+    {
+      double sindomg=sin(domg);
+      r=-omg*omg*omg*(1-1.0/(1.0*N*N))/3*M_PI/N/sindomg/sindomg;
+    }
+    else
+      r=0;
+  }
+  return r;
+}//dsincd_unn
+
+/*
+  function ddsincd_unn: 2nd-order derivative of unnormalized discrete sinc function
+
+  In: x, scale (equivalently, window size) N
+
+  Returns the 2nd-order derivative of sincd_unn(x, N)
+*/
+double ddsincd_unn(double x, int N)
+{
+  double r=0;
+  double omg=M_PI*x;
+  double domg=omg/N;
+  double PI2=M_PI*M_PI;
+  double NN=1.0/N/N-1;
+  if (domg==0)
+  {
+    r=PI2*N*NN/3;
+  }
+  else
+  {
+    if (fabs(x)>1e-5)
+    {
+      r=sin(domg)*cos(omg)-sin(omg)*cos(domg)/N;
+    }
+    else
+    {
+      r=omg*omg*omg/N*NN/3;
+    }
+    double ss=sin(omg)*NN;
+    r=-2.0/N*cos(domg)*r/sin(domg)/sin(domg)+ss;
+    r=r*PI2/sin(domg);
+  }
+  return r;
+}//ddsincd_unn
+
+//---------------------------------------------------------------------------
+/*
+  function Window: calculates the cosine-family-windowed spectrum of a complex sinusoid on [0:N-1] at
+  frequency f bins with zero central phase.
+
+  In: f: frequency, in bins
+      N: window size
+      M, c[]: cosine-family window decomposition coefficients
+  Out: x[0...K2-K1] containing the spectrum at bins K1, ..., K2.
+
+  Returns pointer to x. x is created anew if x=0 is specified on start.
+*/
+cdouble* Window(cdouble* x, double f, int N, int M, double* c, int K1, int K2)
+{
+  if (K1<0) K1=0;
+  if (K2>N/2-1) K2=N/2-1;
+
+  if (!x) x=new cdouble[K2-K1+1];
+  memset(x, 0, sizeof(cdouble)*(K2-K1+1));
+
+  for (int l=K1-M; l<=K2+M; l++)
+  {
+    double ang=(f-l)*M_PI;
+    double omg=ang/N;
+		long double si, co, sinn=sin(ang);
+		si=sin(omg), co=cos(omg);
+		double sa=(ang==0)?N:(sinn/si);
+    double saco=sa*co;
+
+    int k1=l-M, k2=l+M;
+    if (k1<K1) k1=K1;
+    if (k2>K2) k2=K2;
+
+    for (int k=k1; k<=k2; k++)
+    {
+      int m=k-l, kt=k-K1;
+      if (m<0) m=-m;
+      if (k%2)
+      {
+        x[kt].x-=c[m]*saco;
+        x[kt].y+=c[m]*sinn;
+      }
+      else
+      {
+        x[kt].x+=c[m]*saco;
+        x[kt].y-=c[m]*sinn;
+      }
+    }
+  }
+  return x;
+}//Window
+
+/*
+  function dWindow: calculates the cosine-family-windowed spectrum and its derivative of a complex
+  sinusoid on [0:N-1] at frequency f bins with zero central phase.
+
+  In: f: frequency, in bins
+      N: window size
+      M, c[]: cosine-family window decomposition coefficients
+  Out: x[0...K2-K1] containing the spectrum at bins K1, ..., K2,
+       dx[0...K2-K1] containing the derivative spectrum at bins K1, ..., K2
+
+  No return value.
+*/
+void dWindow(cdouble* dx, cdouble* x, double f, int N, int M, double* c, int K1, int K2)
+{
+  if (K1<0) K1=0;
+  if (K2>N/2-1) K2=N/2-1;
+  memset(x, 0, sizeof(cdouble)*(K2-K1+1));
+  memset(dx, 0, sizeof(cdouble)*(K2-K1+1));
+
+  for (int l=K1-M; l<=K2+M; l++)
+  {
+    double ang=(f-l), Omg=ang*M_PI, omg=Omg/N;
+		long double si, co, sinn=sin(Omg), cosn=cos(Omg);
+		si=sin(omg), co=cos(omg);
+		double sa=(ang==0)?N:(sinn/si), dsa=dsincd_unn(ang, N);
+    double saco=sa*co, dsaco=dsa*co, sinnpi_n=sinn*M_PI/N, cosnpi=cosn*M_PI;
+
+    int k1=l-M, k2=l+M;
+    if (k1<K1) k1=K1;
+    if (k2>K2) k2=K2;
+
+    for (int k=k1; k<=k2; k++)
+    {
+      int m=k-l, kt=k-K1;
+      if (m<0) m=-m;
+      if (k%2)
+      {
+        x[kt].x-=c[m]*saco;
+        x[kt].y+=c[m]*sinn;
+        dx[kt].x-=c[m]*(-sinnpi_n+dsaco);
+        dx[kt].y+=c[m]*cosnpi;
+      }
+      else
+      {
+        x[kt].x+=c[m]*saco;
+        x[kt].y-=c[m]*sinn;
+        dx[kt].x+=c[m]*(-sinnpi_n+dsaco);
+        dx[kt].y-=c[m]*cosnpi;
+      }
+    }
+  }
+}//dWindow
+
+/*
+  function ddWindow: calculates the cosine-family-windowed spectrum and its 1st and 2nd derivatives of
+  a complex sinusoid on [0:N-1] at frequency f bins with zero central phase.
+
+  In: f: frequency, in bins
+      N: window size
+      M, c[]: cosine-family window decomposition coefficients
+  Out: x[0...K2-K1] containing the spectrum at bins K1, ..., K2,
+       dx[0...K2-K1] containing the derivative spectrum at bins K1, ..., K2
+       ddx[0...K2-K1] containing the 2nd-order derivative spectrum at bins K1, ..., K2
+
+  No return value.
+*/
+void ddWindow(cdouble* ddx, cdouble* dx, cdouble* x, double f, int N, int M, double* c, int K1, int K2)
+{
+  if (K1<0) K1=0;
+  if (K2>N/2-1) K2=N/2-1;
+  memset(x, 0, sizeof(cdouble)*(K2-K1+1));
+  memset(dx, 0, sizeof(cdouble)*(K2-K1+1));
+  memset(ddx, 0, sizeof(cdouble)*(K2-K1+1));
+
+  for (int l=K1-M; l<=K2+M; l++)
+  {
+    double ang=(f-l), Omg=ang*M_PI, omg=Omg/N;
+    long double si, co, sinn=sin(Omg), cosn=cos(Omg);
+    si=sin(omg), co=cos(omg);
+    double sa=(ang==0)?N:(sinn/si), dsa=dsincd_unn(ang, N), ddsa=ddsincd_unn(ang, N);
+    double saco=sa*co, dsaco=dsa*co, sinnpi_n=sinn*M_PI/N, sinnpipi=sinn*M_PI*M_PI, cosnpi=cosn*M_PI,
+           cosnpipi_n=cosnpi*M_PI/N, sipi_n=si*M_PI/N;
+
+    int k1=l-M, k2=l+M;
+    if (k1<K1) k1=K1;
+    if (k2>K2) k2=K2;
+
+    for (int k=k1; k<=k2; k++)
+    {
+      int m=k-l, kt=k-K1;
+      if (m<0) m=-m;
+      if (k%2)
+      {
+        x[kt].x-=c[m]*saco;
+        x[kt].y+=c[m]*sinn;
+        dx[kt].x-=c[m]*(-sinnpi_n+dsaco);
+        dx[kt].y+=c[m]*cosnpi;
+        ddx[kt].x-=c[m]*(-cosnpipi_n+ddsa*co-dsa*sipi_n);
+        ddx[kt].y-=c[m]*sinnpipi;
+      }
+      else
+      {
+        x[kt].x+=c[m]*saco;
+        x[kt].y-=c[m]*sinn;
+        dx[kt].x+=c[m]*(-sinnpi_n+dsaco);
+        dx[kt].y-=c[m]*cosnpi;
+        ddx[kt].x+=c[m]*(-cosnpipi_n+ddsa*co-dsa*sipi_n);
+        ddx[kt].y+=c[m]*sinnpipi;
+      }
+    }
+  }
+}//ddWindow
+
+//---------------------------------------------------------------------------
+/*
+  function IPWindow: computes the truncated inner product of a windowed spectrum with that of a sinusoid
+  at reference frequency f.
+
+  In: x[0:N-1]: input spectrum
+      f: reference frequency, in bins
+      M, c[], iH2: cosine-family window specification parameters
+      K1, K2: spectrum truncation bounds, in bins, inclusive
+      returnamplitude: specifies return value, true for amplitude, false for angle
+
+  Returns the amplitude or phase of the inner product, as specified by $returnamplitude. The return
+  value is interpreted as the actual amplitude/phase of a sinusoid being estimated at f.
+*/
+double IPWindow(double f, cdouble* x, int N, int M, double* c, double iH2, int K1, int K2, bool returnamplitude)
+{
+  cdouble r=IPWindowC(f, x, N, M, c, iH2, K1, K2);
+  double result;
+  if (returnamplitude) result=sqrt(r.x*r.x+r.y*r.y);
+	else result=arg(r);
+  return result;
+}//IPWindow
+//wrapper function
+double IPWindow(double f, void* params)
+{
+  struct l_ip {int N; int k1; int k2; int M; double* c; double iH2; cdouble* x; double dipwindow; double ipwindow;} *p=(l_ip *)params;
+  return IPWindow(f, p->x, p->N, p->M, p->c, p->iH2, p->k1, p->k2, true);
+}//IPWindow
+
+/*
+  function ddIPWindow: computes the norm of the truncated inner product of a windowed spectrum with
+  that of a sinusoid at reference frequency f, as well as its 1st and 2nd derivatives.
+
+  In: x[0:N-1]: input spectrum
+      f: reference frequency, in bins
+      M, c[], iH2: cosine-family window specification parameters
+      K1, K2: spectrum truncation bounds, in bins, inclusive
+  Out: ipwindow and dipwindow: the truncated inner product norm and its derivative
+
+  Returns the 2nd derivative of the norm of the truncated inner product.
+*/
+double ddIPWindow(double f, cdouble* x, int N, int M, double* c, double iH2, int K1, int K2, double& dipwindow, double& ipwindow)
+{
+	if (K1<0) K1=0; if (K2>=N/2) K2=N/2-1;
+	int K=K2-K1+1;
+	cdouble *w=new cdouble[K*3], *dw=&w[K], *ddw=&w[K*2], *lx=&x[K1];
+	ddWindow(ddw, dw, w, f, N, M, c, K1, K2);
+	cdouble r=Inner(K, lx, w), dr=Inner(K, lx, dw), ddr=Inner(K, lx, ddw);
+	delete[] w;
+
+	double R2=~r,
+				 R=sqrt(R2),
+				 dR2=2*(r.x*dr.x+r.y*dr.y),
+				 dR=dR2/(2*R),
+				 ddR2=2*(r.x*ddr.x+r.y*ddr.y+~dr),
+				 ddR=(R*ddR2-dR2*dR)/(2*R2);
+	ipwindow=R*iH2;
+	dipwindow=dR*iH2;
+	return ddR*iH2;
+}//ddIPWindow
+//wrapper function
+double ddIPWindow(double f, void* params)
+{
+	struct l_ip {int N; int k1; int k2; int M; double* c; double iH2; cdouble* x; double dipwindow; double ipwindow;} *p=(l_ip *)params;
+	return ddIPWindow(f, p->x, p->N, p->M, p->c, p->iH2, p->k1, p->k2, p->dipwindow, p->ipwindow);
+}//ddIPWindow
+
+//---------------------------------------------------------------------------
+/*
+  function IPWindowC: computes the truncated inner product of a windowed spectrum with that of a
+  sinusoid at reference frequency f.
+
+  In: x[0:N-1]: input spectrum
+      f: reference frequency, in bins
+      M, c[], iH2: cosine-family window specification parameters
+      K1, K2: spectrum truncation bounds, in bins, inclusive
+
+  Returns the inner product. The return value is interpreted as the actual amplitude-phase factor of a
+  sinusoid being estimated at f.
+*/
+cdouble IPWindowC(double f, cdouble* x, int N, int M, double* c, double iH2, int K1, int K2)
+{
+	if (K1<0) K1=0; if (K2>=N/2) K2=N/2-1;
+	int K=K2-K1+1;
+	cdouble *w=new cdouble[K];
+	cdouble *lx=&x[K1], result=0;
+	Window(w, f, N, M, c, K1, K2);
+	for (int k=0; k<K; k++) result+=lx[k]^w[k];
+	delete[] w;
+	result*=iH2;
+	return result;
+}//IPWindowC
+
+//---------------------------------------------------------------------------
+/*
+  function sIPWindow: computes the total energy of truncated inner products between multiple windowed
+  spectra and that of a sinusoid at a reference frequency f. This does not consider phase alignment
+  between the spectra, supposedly measured at a sequence of known instants.
+
+  In: x[L][N]: input spectra
+      f: reference frequency, in bins
+      M, c[], iH2: cosine-family window specification parameters
+      K1, K2: spectrum truncation bounds, in bins, inclusive
+  Out: lmd[L]: the actual individual inner products representing actual ampltiude-phase factors (optional)
+
+  Returns the energy of the vector of inner products.
+*/
+double sIPWindow(double f, int L, cdouble** x, int N, int M, double* c, double iH2, int K1, int K2, cdouble* lmd)
+{
+	double sip=0;
+	if (K1<0) K1=0; if (K2>=N/2) K2=N/2-1;
+	int K=K2-K1+1;
+	cdouble *w=new cdouble[K];
+	Window(w, f, N, M, c, K1, K2);
+	for (int l=0; l<L; l++)
+	{
+		cdouble *lx=&x[l][K1];
+		cdouble r=Inner(K, lx, w);
+		if (lmd) lmd[l]=r*iH2;
+		sip+=~r;
+	}
+	sip*=iH2;
+	delete[] w;
+	return sip;
+}//sIPWindow
+//wrapper function
+double sIPWindow(double f, void* params)
+{
+	struct l_ip {int N; int k1; int k2; int M; double* c; double iH2; int Fr; cdouble** x; double dipwindow; double ipwindow; cdouble* lmd;} *p=(l_ip *)params;
+	return sIPWindow(f, p->Fr, p->x, p->N, p->M, p->c, p->iH2, p->k1, p->k2, p->lmd);
+}//sIPWindow
+
+/*
+  function dsIPWindow: computes the total energy of truncated inner products between multiple windowed
+  spectra and that of a sinusoid at a reference frequency f, as well as its derivative. This does not
+  consider phase synchronization between the spectra, supposedly measured at a sequence of known
+  instants.
+
+  In: x[L][N]: input spectra
+      f: reference frequency, in bins
+      M, c[], iH2: cosine-family window specification parameters
+      K1, K2: spectrum truncation bounds, in bins, inclusive
+  Out: sip, the energy of the vector of inner products.
+
+  Returns the derivative of the energy of the vector of inner products.
+*/
+double dsIPWindow(double f, int L, cdouble** x, int N, int M, double* c, double iH2, int K1, int K2, double& sip)
+{
+	if (K1<0) K1=0; if (K2>=N/2) K2=N/2-1;
+	int K=K2-K1+1;
+	cdouble *w=new cdouble[K*2], *dw=&w[K];
+	dWindow(dw, w, f, N, M, c, K1, K2);
+	double dsip; sip=0;
+	for (int l=0; l<L; l++)
+	{
+		cdouble* lx=&x[l][K1];
+		cdouble r=Inner(K, lx, w), dr=Inner(K, lx, dw);
+		double R2=~r, dR2=2*(r.x*dr.x+r.y*dr.y);
+		sip+=R2, dsip+=dR2;
+	}
+	sip*=iH2, dsip*=iH2;
+	delete[] w;
+	return dsip;
+}//dsIPWindow
+//wrapper function
+double dsIPWindow(double f, void* params)
+{
+	struct l_ip1 {int N; int k1; int k2; int M; double* c; double iH2; int Fr; cdouble** x; double sip;} *p=(l_ip1 *)params;
+	return dsIPWindow(f, p->Fr, p->x, p->N, p->M, p->c, p->iH2, p->k1, p->k2, p->sip);
+}//dsIPWindow
+
+/*
+  function dsdIPWindow_unn: computes the energy of unnormalized truncated inner products between a given
+  windowed spectrum and that of a sinusoid at a reference frequency f, as well as its 1st and 2nd
+  derivatives. "Unnormalized" indicates that the inner product cannot be taken as the actual amplitude-
+  phase factor of a sinusoid, but deviate from that by an unspecified factor.
+
+  In: x[N]: input spectrum
+      f: reference frequency, in bins
+      M, c[], iH2: cosine-family window specification parameters
+      K1, K2: spectrum truncation bounds, in bins, inclusive
+  Out: sipwindow and dsipwindow, the energy and its derivative of the unnormalized inner product.
+
+  Returns the 2nd derivative of the inner product.
+*/
+double ddsIPWindow_unn(double f, cdouble* x, int N, int M, double* c, int K1, int K2, double& dsipwindow, double& sipwindow, cdouble* w_unn)
+{
+	if (K1<0) K1=0; if (K2>=N/2) K2=N/2-1;
+	int K=K2-K1+1;
+
+	cdouble *w=new cdouble[K*3], *dw=&w[K], *ddw=&w[K*2];
+
+	ddWindow(ddw, dw, w, f, N, M, c, K1, K2);
+
+	double rr=0, ri=0, drr=0, dri=0, ddrr=0, ddri=0;
+  cdouble *lx=&x[K1];
+  for (int k=0; k<K; k++)
+  {
+		rr+=lx[k].x*w[k].x+lx[k].y*w[k].y;
+    ri+=lx[k].y*w[k].x-lx[k].x*w[k].y;
+    drr+=lx[k].x*dw[k].x+lx[k].y*dw[k].y;
+    dri+=lx[k].y*dw[k].x-lx[k].x*dw[k].y;
+		ddrr+=lx[k].x*ddw[k].x+lx[k].y*ddw[k].y;
+		ddri+=lx[k].y*ddw[k].x-lx[k].x*ddw[k].y;
+	}
+	delete[] w;
+
+	double R2=rr*rr+ri*ri,
+         dR2=2*(rr*drr+ri*dri),
+         ddR2=2*(rr*ddrr+ri*ddri+drr*drr+dri*dri);
+	sipwindow=R2;
+  dsipwindow=dR2;
+  if (w_unn) w_unn->x=rr, w_unn->y=ri;
+	return ddR2;
+}//ddsIPWindow_unn
+
+/*
+  function ddsIPWindow: computes the total energy of truncated inner products between multiple windowed
+  spectra and that of a sinusoid at a reference frequency f, as well as its 1st and 2nd derivatives.
+  This does not consider phase synchronization between the spectra, supposedly measured at a sequence
+  of known instants.
+
+  In: x[L][N]: input spectra
+      f: reference frequency, in bins
+      M, c[], iH2: cosine-family window specification parameters
+      K1, K2: spectrum truncation bounds, in bins, inclusive
+  Out: sip and dsip, the energy of the vector of inner products and its derivative.
+
+  Returns the 2nd derivative of the energy of the vector of inner products.
+*/
+double ddsIPWindow(double f, int L, cdouble** x, int N, int M, double* c, double iH2, int K1, int K2, double& dsip, double& sip)
+{
+  if (K1<0) K1=0; if (K2>=N/2) K2=N/2-1;
+  int K=K2-K1+1;
+	cdouble *w=new cdouble[K*3], *dw=&w[K], *ddw=&w[K*2];
+	ddWindow(ddw, dw, w, f, N, M, c, K1, K2);
+  double ddsip=0; dsip=sip=0;
+  for (int l=0; l<L; l++)
+  {
+		cdouble* lx=&x[l][K1];
+		cdouble r=Inner(K, lx, w), dr=Inner(K, lx, dw), ddr=Inner(K, lx, ddw);
+		double R2=~r, dR2=2*(r.x*dr.x+r.y*dr.y), ddR2=2*(r.x*ddr.x+r.y*ddr.y+~dr);
+    sip+=R2, dsip+=dR2, ddsip+=ddR2;
+	}
+  sip*=iH2, dsip*=iH2, ddsip*=iH2;
+	delete[] w;
+  return ddsip;
+}//ddsIPWindow
+//wrapper function
+double ddsIPWindow(double f, void* params)
+{
+  struct l_ip1 {int N; int k1; int k2; int M; double* c; double iH2; int Fr; cdouble** x; double dsip; double sip;} *p=(l_ip1 *)params;
+	return ddsIPWindow(f, p->Fr, p->x, p->N, p->M, p->c, p->iH2, p->k1, p->k2, p->dsip, p->sip);
+}//ddsIPWindow
+
+//---------------------------------------------------------------------------
+/*
+  function sIPWindowC: computes the total energy of truncated inner products between multiple frames of
+  a spectrogram and multiple frames of a spectrogram of a sinusoid at a reference frequency f.
+
+  In: x[L][N]: the spectrogram
+      offst_rel: frame offset, relative to frame size
+      f: reference frequency, in bins
+      M, c[], iH2: cosine-family window specification parameters
+      K1, K2: spectrum truncation bounds, in bins, inclusive
+  Out: lmd[L]: the actual individual inner products representing actual ampltiude-phase factors (optional)
+
+  Returns the energy of the vector of inner products.
+*/
+double sIPWindowC(double f, int L, double offst_rel, cdouble** x, int N, int M, double* c, double iH2, int K1, int K2, cdouble* lmd)
+{
+	if (K1<0) K1=0; if (K2>=N/2) K2=N/2-1;
+	int K=K2-K1+1;
+	cdouble *w=new cdouble[K];
+	double Cr=0;
+	cdouble Cc=0;
+	Window(w, f, N, M, c, K1, K2);
+	for (int l=0; l<L; l++)
+	{
+		cdouble *lx=&x[l][K1];
+		cdouble r=Inner(K, lx, w);
+		Cr+=~r;
+		double ph=-4*M_PI*f*offst_rel*l;
+		cdouble r2=r*r;
+		Cc+=r2.rotate(ph);
+		if (lmd) lmd[l]=r;
+	}
+	delete[] w;
+	double result=0.5*iH2*(Cr+abs(Cc));
+	if (lmd)
+	{
+		double absCc=abs(Cc), hiH2=0.5*iH2;
+		cdouble ej2ph=Cc/absCc;
+		for (int l=0; l<L; l++)
+		{
+      double ph=4*M_PI*f*offst_rel*l;
+			lmd[l]=hiH2*(lmd[l]+(ej2ph**lmd[l]).rotate(ph));
+    }
+	}
+  return result;
+}//sIPWindowC
+//wrapper function
+double sIPWindowC(double f, void* params)
+{
+  struct l_ip {int N; int k1; int k2; int M; double* c; double iH2; int L; double offst_rel; cdouble** x; double dipwindow; double ipwindow;} *p=(l_ip *)params;
+	return sIPWindowC(f, p->L, p->offst_rel, p->x, p->N, p->M, p->c, p->iH2, p->k1, p->k2);
+}//sIPWindowC
+
+/*
+  function dsIPWindowC: computes the total energy of truncated inner products between multiple frames of
+  a spectrogram and multiple frames of a spectrogram of a sinusoid at a reference frequency f, together
+  with its derivative.
+
+  In: x[L][N]: the spectrogram
+      offst_rel: frame offset, relative to frame size
+      f: reference frequency, in bins
+      M, c[], iH2: cosine-family window specification parameters
+      K1, K2: spectrum truncation bounds, in bins, inclusive
+  Out: sip: energy of the vector of the inner products
+
+  Returns the 1st derivative of the energy of the vector of inner products.
+*/
+double dsIPWindowC(double f, int L, double offst_rel, cdouble** x, int N, int M, double* c, double iH2, int K1, int K2, double& sip)
+{
+  if (K1<0) K1=0; if (K2>=N/2) K2=N/2-1;
+	int K=K2-K1+1;
+
+	cdouble *w=new cdouble[K*2], *dw=&w[K];
+  dWindow(dw, w, f, N, M, c, K1, K2);
+	double Cr=0, dCr=0;
+  cdouble Cc=0, dCc=0;
+	for (int l=0; l<L; l++)
+  {
+		cdouble *lx=&x[l][K1];
+    cdouble r=Inner(K, lx, w), dr=Inner(K, lx, dw);
+		Cr+=~r; dCr+=2*(r.x*dr.x+r.y*dr.y);
+    int two=2;
+		cdouble r2=r*r, dr2=r*dr*two;
+    double lag=-4*M_PI*offst_rel*l, ph=lag*f;
+		Cc=Cc+cdouble(r2).rotate(ph), dCc=dCc+(dr2+cdouble(0,lag)*r2).rotate(ph);
+  }
+	double Cc2=~Cc, dCc2=2*(Cc.x*dCc.x+Cc.y*dCc.y);
+  double Cc1=sqrt(Cc2), dCc1=dCc2/(2*Cc1);
+	sip=0.5*iH2*(Cr+Cc1);
+  double dsip=0.5*iH2*(dCr+dCc1);
+	delete[] w;
+	return dsip;
+}//dsIPWindowC
+//wrapper function
+double dsIPWindowC(double f, void* params)
+{
+  struct l_ip {int N; int k1; int k2; int M; double* c; double iH2; int L; double offst_rel; cdouble** x; double sip;} *p=(l_ip *)params;
+	return dsIPWindowC(f, p->L, p->offst_rel, p->x, p->N, p->M, p->c, p->iH2, p->k1, p->k2, p->sip);
+}//dsIPWindowC
+
+/*
+  function ddsIPWindowC: computes the total energy of truncated inner products between multiple frames
+  of a spectrogram and multiple frames of a spectrogram of a sinusoid at a reference frequency f,
+  together with its 1st and 2nd derivatives.
+
+  In: x[L][N]: the spectrogram
+      offst_rel: frame offset, relative to frame size
+      f: reference frequency, in bins
+      M, c[], iH2: cosine-family window specification parameters
+      K1, K2: spectrum truncation bounds, in bins, inclusive
+  Out: sipwindow, dsipwindow: energy of the vector of the inner products and its derivative
+
+  Returns the 2nd derivative of the energy of the vector of inner products.
+*/
+double ddsIPWindowC(double f, int L, double offst_rel, cdouble** x, int N, int M, double* c, double iH2, int K1, int K2, double& dsipwindow, double& sipwindow)
+{
+  if (K1<0) K1=0; if (K2>=N/2) K2=N/2-1;
+	int K=K2-K1+1;
+
+	cdouble *w=new cdouble[K*3], *dw=&w[K], *ddw=&w[K*2];
+  ddWindow(ddw, dw, w, f, N, M, c, K1, K2);
+	double Cr=0, dCr=0, ddCr=0;
+  cdouble Cc=0, dCc=0, ddCc=0;
+	for (int l=0; l<L; l++)
+  {
+		cdouble *lx=&x[l][K1];
+    cdouble r=Inner(K, lx, w), dr=Inner(K, lx, dw), ddr=Inner(K, lx, ddw);
+		Cr+=~r; dCr+=2*(r.x*dr.x+r.y*dr.y); ddCr+=2*(r.x*ddr.x+r.y*ddr.y+~dr);
+    int two=2;
+		cdouble r2=r*r, dr2=r*dr*two, ddr2=(dr*dr+r*ddr)*two;
+    double lag=-4*M_PI*offst_rel*l, ph=lag*f;
+		Cc=Cc+cdouble(r2).rotate(ph), dCc=dCc+(dr2+cdouble(0,lag)*r2).rotate(ph), ddCc=ddCc+(ddr2+cdouble(0,2*lag)*dr2-r2*lag*lag).rotate(ph);
+  }
+	double Cc2=~Cc, dCc2=2*(Cc.x*dCc.x+Cc.y*dCc.y), ddCc2=2*(Cc.x*ddCc.x+Cc.y*ddCc.y+~dCc);
+  double Cc1=sqrt(Cc2), dCc1=dCc2/(2*Cc1), ddCc1=(Cc1*ddCc2-dCc2*dCc1)/(2*Cc2);
+	sipwindow=0.5*iH2*(Cr+Cc1);
+  dsipwindow=0.5*iH2*(dCr+dCc1);
+	double ddsipwindow=0.5*iH2*(ddCr+ddCc1);
+	delete[] w;
+	return ddsipwindow;
+}//ddsIPWindowC
+//wrapper function
+double ddsIPWindowC(double f, void* params)
+{
+	struct l_ip {int N; int k1; int k2; int M; double* c; double iH2; int L; double offst_rel; cdouble** x; double dipwindow; double ipwindow;} *p=(l_ip *)params;
+  return ddsIPWindowC(f, p->L, p->offst_rel, p->x, p->N, p->M, p->c, p->iH2, p->k1, p->k2, p->dipwindow, p->ipwindow);
+}//ddsIPWindowC
+
+//--------------------------------------------------------------------------
+/*
+	Least-square-error sinusoid detection function
+
+	version1: picking the highest peak and take measurement of a single sinusoid
+	version2: given a rough peak location and take measurement of a single sinusoid
+
+  Complex spectrum x is calculated using N data points windowed by a window function that is specified
+  by the parameter set (M, c, iH2). c[0:M] is	provided according to Table 3 in the transfer report, on
+  pp.11. iH2 is simply 1/H2, where H2 can be calculated using formula (2.17) on pp.12.
+
+  f & epf are given/returned in bins.
+
+  Further reading: "Least-square-error estimation of sinusoids.pdf"
+*/
+
+/*
+  function LSESinusoid: LSE estimation of the predominant stationary sinusoid.
+
+  In: x[N]: windowed spectrum
+      B: spectral truncation half width, in bins.
+      M, c[], iH2: cosine-family window specification parameters
+      epf: frequency error tolerance, in bins
+  Out: a and pp: amplitude and phase estimates
+
+  Returns the frequency estimate, in bins.
+*/
+double LSESinusoid(cdouble* x, int N, double B, int M, double* c, double iH2, double& a, double& pp, double epf)
+{
+  struct l_hx {int N; int k1; int k2; int M; double* c; double iH2; cdouble* x; double dhxpeak; double hxpeak;} p={N, 0, 0, M, c, iH2, x, 0, 0}; //(l_hx *)&params;
+  int dfshift=int(&((l_hx*)0)->dhxpeak);
+
+  int inp;
+  double minp=0;
+  for (int i=0; i<N; i++)
+  {
+    double lf=i, tmp;
+    p.k1=ceil(lf-B); if (p.k1<0) p.k1=0;
+    p.k2=floor(lf+B); if (p.k2>=p.N/2) p.k2=p.N/2-1;
+    tmp=IPWindow(lf, &p);
+    if (minp<tmp) inp=i, minp=tmp;
+  }
+
+  double f=inp;
+  p.k1=ceil(inp-B); if (p.k1<0) p.k1=0;
+  p.k2=floor(inp+B); if (p.k2>=p.N/2) p.k2=p.N/2-1;
+  double tmp=Newton(f, ddIPWindow, &p, dfshift, epf);
+  if (tmp==-1)
+  {
+    Search1Dmax(f, &p, IPWindow, inp-1, inp+1, &a, epf);
+  }
+  else
+    a=p.hxpeak;
+  pp=IPWindow(f, x, N, M, c, iH2, p.k1, p.k2, false);
+  return f;
+}//LSESinusoid
+
+/*function LSESinusoid: LSE estimation of stationary sinusoid near a given initial frequency.
+
+  In: x[N]: windowed spectrum
+      f: initial frequency, in bins
+      B: spectral truncation half width, in bins.
+      M, c[], iH2: cosine-family window specification parameters
+      epf: frequency error tolerance, in bins
+  Out: f, a and pp: frequency, amplitude and phase estimates
+
+  No return value.
+*/
+void LSESinusoid(double& f, cdouble* x, int N, double B, int M, double* c, double iH2, double& a, double& pp, double epf)
+{
+  struct l_hx {int N; int k1; int k2; int M; double* c; double iH2; cdouble* x; double dhxpeak; double hxpeak;} p={N, 0, 0, M, c, iH2, x, 0, 0};
+  int dfshift=int(&((l_hx*)0)->dhxpeak);
+
+  double inp=f;
+  p.k1=ceil(inp-B); if (p.k1<0) p.k1=0;
+  p.k2=floor(inp+B); if (p.k2>=p.N/2) p.k2=p.N/2-1;
+  double tmp=Newton(f, ddIPWindow, &p, dfshift, epf);
+  if (tmp==-1)
+  {
+    Search1Dmax(f, &p, IPWindow, inp-1, inp+1, &a, epf);
+  }
+  else
+    a=p.hxpeak;
+  pp=IPWindow(f, x, N, M, c, iH2, p.k1, p.k2, false);
+}//LSESinusoid
+
+/*
+  function LSESinusoid: LSE estimation of stationary sinusoid predominant within [f1, f2].
+
+  In: x[N]: windowed spectrum
+      [f1, f2]: frequency range
+      B: spectral truncation half width, in bins.
+      M, c[], iH2: cosine-family window specification parameters
+      epf: frequency error tolerance, in bins
+  Out: a and pp: amplitude and phase estimates
+
+  Returns the frequency estimate, in bins.
+*/
+double LSESinusoid(int f1, int f2, cdouble* x, int N, double B, int M, double* c, double iH2, double& a, double& pp, double epf)
+{
+  struct l_hx {int N; int k1; int k2; int M; double* c; double iH2; cdouble* x; double dhxpeak; double hxpeak;} p={N, 0, 0, M, c, iH2, x, 0, 0};
+  int dfshift=int(&((l_hx*)0)->dhxpeak);
+
+  int inp;
+  double minp=0;
+  for (int i=f1; i<f2; i++)
+  {
+    double lf=i, tmp;
+    p.k1=ceil(lf-B); if (p.k1<0) p.k1=0;
+    p.k2=floor(lf+B); if (p.k2>=p.N/2) p.k2=p.N/2-1;
+    tmp=IPWindow(lf, &p);
+    if (minp<tmp) inp=i, minp=tmp;
+  }
+
+  double f=inp;
+  p.k1=ceil(inp-B); if (p.k1<0) p.k1=0;
+  p.k2=floor(inp+B); if (p.k2>=p.N/2) p.k2=p.N/2-1;
+  double tmp=Newton(f, ddIPWindow, &p, dfshift, epf);
+  if (tmp==-1)
+  {
+    Search1Dmax(f, &p, IPWindow, inp-1, inp+1, &a, epf);
+  }
+  else
+    a=p.hxpeak;
+  pp=IPWindow(f, x, N, M, c, iH2, p.k1, p.k2, false);
+  return f;
+}//LSESinusoid
+
+/*
+  function LSESinusoid: LSE estimation of stationary sinusoid near a given initial frequency within [f1,
+  f2].
+
+  In: x[N]: windowed spectrum
+      f: initial frequency, in bins
+      [f1, f2]: frequency range
+      B: spectral truncation half width, in bins.
+      M, c[], iH2: cosine-family window specification parameters
+      epf: frequency error tolerance, in bins
+  Out: f, a and pp: frequency, amplitude and phase estimates
+
+  Returns 1 if managed to find a sinusoid, 0 if not, upon which $a and $pp are estimated at the initial
+  f.
+*/
+int LSESinusoid(double& f, double f1, double f2, cdouble* x, int N, double B, int M, double* c, double iH2, double& a, double& pp, double epf)
+{
+  struct l_hx {int N; int k1; int k2; int M; double* c; double iH2; cdouble* x; double dhxpeak; double hxpeak;} p={N, 0, 0, M, c, iH2, x, 0, 0};//(l_hx *)&params;
+  int dfshift=int(&((l_hx*)0)->dhxpeak);
+
+  int result=0;
+  double inp=f;
+  p.k1=ceil(inp-B); if (p.k1<0) p.k1=0;
+  p.k2=floor(inp+B); if (p.k2>=p.N/2) p.k2=p.N/2-1;
+  double tmp=Newton(f, ddIPWindow, &p, dfshift, epf, 100, 1e-256, f1, f2);
+  if (tmp!=-1 && f>f1 && f<f2)
+  {
+    result=1;
+    a=p.hxpeak;
+    pp=IPWindow(f, x, N, M, c, iH2, p.k1, p.k2, false);
+  }
+  else
+  {
+    Search1DmaxEx(f, &p, IPWindow, f1, f2, &a, epf);
+    if (f<=f1 || f>=f2)
+    {
+      f=inp;
+      cdouble r=IPWindowC(f, x, N, M, c, iH2, p.k1, p.k2);
+      a=abs(r);
+      pp=arg(r);
+    }
+    else
+    {
+      result=1;
+      pp=IPWindow(f, x, N, M, c, iH2, p.k1, p.k2, false);
+    }
+  }
+  return result;
+}//LSESinusoid
+
+/*
+  function LSESinusoidMP: LSE estimation of a stationary sinusoid from multi-frames spectrogram without
+  considering phase-frequency consistency across frames.
+
+  In: x[Fr][N]: spectrogram
+      f: initial frequency, in bins
+      [f1, f2]: frequency range
+      B: spectral truncation half width, in bins.
+      M, c[], iH2: cosine-family window specification parameters
+      epf: frequency error tolerance, in bins
+  Out: f, a[Fr] and ph[Fr]: frequency, amplitudes and phase angles estimates
+
+  Returns an error bound of the frequency estimate.
+*/
+double LSESinusoidMP(double& f, double f1, double f2, cdouble** x, int Fr, int N, double B, int M, double* c, double iH2, double* a, double* ph, double epf)
+{
+  struct l_ip1 {int N; int k1; int k2; int M; double* c; double iH2; int L; cdouble** x; double dsip; double sip; cdouble* lmd;} p={N, 0, 0, M, c,iH2, Fr, x, 0, 0, 0};
+  int dfshift=int(&((l_ip1*)0)->dsip), fshift=int(&((l_ip1*)0)->sip);
+
+  double inp=f;
+  p.k1=ceil(inp-B); if (p.k1<0) p.k1=0;
+  p.k2=floor(inp+B); if (p.k2>=p.N/2) p.k2=p.N/2-1;
+  double errf=Newton1dmax(f, f1, f2, ddsIPWindow, &p, dfshift, fshift, dsIPWindow, dfshift, epf);
+  if (errf<0) errf=Search1Dmax(f, &p, sIPWindow, f1, f2, a, epf);
+  if (a || ph)
+  {
+    for (int fr=0; fr<Fr; fr++)
+    {
+      cdouble r=IPWindowC(f, x[fr], N, M, c, iH2, p.k1, p.k2);
+      if (a) a[fr]=abs(r);
+      if (ph) ph[fr]=arg(r);
+    }
+  }
+  return errf;
+}//LSESinusoidMP
+
+/*
+  function LSESinusoidMP: LSE estimation of a stationary sinusoid from multi-frames spectrogram without
+  considering phase-frequency consistency across frames.
+
+  In: x[Fr][N]: spectrogram
+      f: initial frequency, in bins
+      [f1, f2]: frequency range
+      B: spectral truncation half width, in bins.
+      M, c[], iH2: cosine-family window specification parameters
+      epf: frequency error tolerance, in bins
+  Out: f, a[Fr] and ph[Fr]: frequency, amplitudes and phase angles estimates
+
+  Returns an error bound of the frequency estimate. Although the frequencies are estimated assuming
+  cross-frame frequency-phase consistency, the final output phase angles are reestimated independently
+  for each frame using the frequency estimate.
+*/
+double LSESinusoidMPC(double& f, double f1, double f2, cdouble** x, int Fr, int N, int Offst, double B, int M, double* c, double iH2, double* a, double* ph, double epf)
+{
+  struct l_ip {int N; int k1; int k2; int M; double* c; double iH2; int L; double offst_rel; cdouble** x; double sdip; double sip;}
+    p={N, 0, 0, M, c,iH2, Fr, Offst*1.0/N, x, 0, 0};
+	int dfshift=int(&((l_ip*)0)->sdip), fshift=int(&((l_ip*)0)->sip);
+
+  double inp=f;
+  p.k1=ceil(inp-B); if (p.k1<0) p.k1=0;
+  p.k2=floor(inp+B); if (p.k2>=p.N/2) p.k2=p.N/2-1;
+  double errf=Newton1dmax(f, f1, f2, ddsIPWindowC, &p, dfshift, fshift, dsIPWindowC, dfshift, epf);
+  if (errf<0) errf=Search1Dmax(f, &p, sIPWindowC, f1, f2, a, epf);
+  if (a || ph)
+  {
+    cdouble* lmd=new cdouble[Fr];
+    sIPWindowC(f, Fr, Offst*1.0/N, x, N, M, c, iH2, p.k1, p.k2, lmd);
+    for (int fr=0; fr<Fr; fr++)
+    {
+      lmd[fr]=IPWindowC(f, x[fr], N, M, c, iH2, p.k1, p.k2);
+
+      if (a) a[fr]=abs(lmd[fr]);
+      if (ph) ph[fr]=arg(lmd[fr]);
+    }
+    delete[] lmd;
+  }
+  return errf;
+}//LSESinusoidMPC
+
+//---------------------------------------------------------------------------
+/*
+  function IPMulti: least square estimation of multiple sinusoids, given their frequencies and an energy
+  suppression index of eps, i.e. the least square error is minimized with an additional eps*||lmd||^2
+  term.
+
+  In: x[Wid]: spectrum
+      f[I]: frequencies
+      M, c[]: cosine-family window specification parameters
+      K1, K2: spectral truncation range, i.e. bins outside [K1, K2] are ignored
+      eps: energy suppression factor
+  Out: lmd[I]: amplitude-phase factors
+
+  No return value.
+*/
+void IPMulti(int I, double* f, cdouble* lmd, cdouble* x, int Wid, int K1, int K2, int M, double* c, double eps)
+{
+  if (K1<0) K1=0; if (K2>=Wid/2) K2=Wid/2-1; int K=K2-K1+1;
+  MList* List=new MList;
+  cdouble** Allocate2L(cdouble, I, K, wt, List);
+  for (int i=0; i<I; i++) Window(wt[i], f[i], Wid, M, c, K1, K2);
+  cdouble** whw=MultiplyXcXt(I, K, wt, List);
+  cdouble* whx=MultiplyXcy(I, K, wt, &x[K1], List);
+  for (int i=0; i<I; i++) whw[i][i]+=eps;
+  GECP(I, lmd, whw, whx);
+  delete List;
+}//IPMulti
+
+/*
+  function IPMulti: least square estimation of multiple sinusoids, given their frequencies and an energy
+  suppression index of eps, and optionally returns residue and sensitivity indicators for each sinusoid.
+
+  In: x[Wid]: spectrum
+      f[I]: frequencies
+      M, c[]: cosine-family window specification parameters
+      K1, K2: spectral truncation range, i.e. bins outside [K1, K2] are ignored
+      eps: energy suppression factor
+  Out: lmd[I]: amplitude-phase factors
+       sens[I]: sensitivity indicators
+       r1[I]: residue indicators, measured by correlating residue with sinusoid spectra, optional
+
+  No return value. Sensibitily is computed BEFORE applying eps.
+*/
+void IPMulti(int I, double* f, cdouble* lmd, cfloat* x, int Wid, int K1, int K2, int M, double* c, double eps, double* sens, double* r1)
+{
+  if (K1<0) K1=0; if (K2>=Wid/2) K2=Wid/2-1; int K=K2-K1+1;
+  MList* List=new MList;
+  cdouble** Allocate2L(cdouble, I, K, wt, List);
+  for (int i=0; i<I; i++) Window(wt[i], f[i], Wid, M, c, K1, K2);
+  cdouble** whw=MultiplyXcXt(I, K, wt, List);
+
+	//*computes sensitivity if required
+  if (sens)
+  {
+    cdouble** iwhw=Copy(I, whw, List);
+    GICP(I, iwhw);
+    cdouble** u=MultiplyXYc(I, I, K, iwhw, wt, List);
+    for (int i=0; i<I; i++)
+    {
+			sens[i]=0; for (int k=0; k<K; k++) sens[i]+=~u[i][k]; sens[i]=sqrt(sens[i]);
+    }
+	} //*/
+  cdouble* whx=MultiplyXcy(I, K, wt, &x[K1], List);
+  for (int i=0; i<I; i++) whw[i][i]+=eps;
+  GECP(I, lmd, whw, whx);
+  //compute residue if required
+  if (r1)
+  {
+    cdouble* wlmd=MultiplyXty(K, I, wt, lmd, List); //reconstruct
+    for (int k=0; k<K; k++) wlmd[k]=wlmd[k]-x[K1+k]; //-residue
+    for (int i=0; i<I; i++) //r1[i]=Inner(K, wlmd, wt[i]).abs(); //-residue weighted by window
+    {
+      r1[i]=0;
+      for (int k=0; k<K; k++) r1[i]+=abs(wlmd[k])*abs(wt[i][k]);
+    }
+  }
+  delete List;
+}//IPMulti
+
+/*
+  function IPMultiSens: computes the sensitivity of the least square estimation of multiple sinusoids given
+  their frequencies .
+
+  In: f[I]: frequencies
+      M, c[]: cosine-family window specification parameters
+      K1, K2: spectral truncation range, i.e. bins outside [K1, K2] are ignored
+      eps: energy suppression factor
+  Out: sens[I]: sensitivity indicators
+
+  No return value. Sensibility is computed AFTER applying eps
+*/
+void IPMultiSens(int I, double* f, int Wid, int K1, int K2, int M, double* c, double* sens, double eps)
+{
+  if (K1<0) K1=0; if (K2>=Wid/2) K2=Wid/2-1; int K=K2-K1+1;
+  MList* List=new MList;
+  cdouble** Allocate2L(cdouble, I, K, wt, List);
+  for (int i=0; i<I; i++) Window(wt[i], f[i], Wid, M, c, K1, K2);
+
+  cdouble** whw=MultiplyXcXt(I, K, wt, List);
+  for (int i=0; i<I; i++) whw[i][i]+=eps;
+
+  cdouble** iwhw=Copy(I, whw, List);
+  GICP(I, iwhw);
+  cdouble** u=MultiplyXYc(I, I, K, iwhw, wt, List);
+  for (int i=0; i<I; i++)
+	{
+    sens[i]=0; for (int k=0; k<K; k++) sens[i]+=~u[i][k]; sens[i]=sqrt(sens[i]);
+  }
+  delete List;
+}//IPMultiSens
+
+/*
+  function IPMulti: least square estimation of multi-sinusoids with GIVEN frequencies. This version
+  operates in groups at least B bins from each other, rather than LSE all frequencies together.
+
+  In: x[Wid]: spectrum
+      f[I]: frequencies, must be ordered low to high.
+      B: number of bins beyond which sinusoids are treated as non-interfering
+      M, c[], iH2: cosine-family window specification parameters
+  Out: lmd[I]: amplitude-phase factors
+
+  Returns 0.
+*/
+double IPMulti(int I, double* f, cdouble* lmd, cdouble* x, int Wid, int M, double* c, double iH2, int B)
+{
+  int i=0, ist=0;
+  double Bw=B;
+  while (i<I)
+  {
+    if ((i>0 && f[i]-f[i-1]>Bw) || i==I-1)
+    {
+      if (i==I-1) i++;
+      //process frequencies from ist to i-1
+      if (i-1==ist) //one sinusoid
+      {
+        double fb=f[ist]; int K1=floor(fb-B+0.5), K2=floor(fb+B+0.5);
+        lmd[ist]=IPWindowC(fb, x, Wid, M, c, iH2, K1, K2);
+      }
+      else
+      {
+        MList* List=new MList;
+        int N=i-ist, K1=floor(f[ist]-B+0.5), K2=floor(f[i-1]+B+0.5), K=K2-K1+1;
+        cdouble** Allocate2L(cdouble, N, K, wt, List);
+        for (int n=0; n<N; n++) Window(wt[n], f[ist+n], Wid, M, c, K1, K2);
+        cdouble* whx=MultiplyXcy(N, K, wt, &x[K1], List); //w*'x=(wt*)x
+        cdouble** whw=MultiplyXcXt(N, K, wt, List);
+          /*debug cdouble** C=SubMatrix(0, whw, 1, 4, 1, 4, List); cdouble** C2=SubMatrix(0, whw, 1, 4, 1, 4, List); cdouble** Bh=SubMatrix(0, whw, 1, 4, 0, 1, List); cdouble* Y2=SubVector(0, whx, 1, 4);
+          cdouble x2[4]; cdouble x1=lmd[ist], Bhx1[4], dx2[4]; for (int j=0; j<4; j++) Bhx1[j]=x1^Bh[j][0]; GECP(4, x2, C, Y2); GECP(4, dx2, C2, Bhx1);*/
+        GECP(N, &lmd[ist], whw, whx); //solving complex linear system (w*'w)a=w*'x
+        delete List;
+      }
+      ist=i;
+    }
+    i++;
+  }
+  return 0;
+}//IPMulti
+
+/*
+  function IPMulti_Direct: LSE estimation of multiple sinusoids given frequencies AND PHASES (direct
+  method)
+
+  In: x[Wid]: spectrum
+      f[I], ph[I]: frequencies and phase angles.
+      B: spectral truncation half width, in bins; sinusoids over 3B bins apart are regarded non-interfering
+      M, c[], iH2: cosine-family window specification parameters
+  Out: a[I]: amplitudes
+
+  Returns square norm of the residue.
+*/
+double IPMulti_Direct(int I, double* f, double* ph, double* a, cdouble* x, int Wid, int M, double* c, double iH2, int B)
+{
+	MList* List=new MList;
+  int i=0, ist=0, hWid=Wid/2;
+  cdouble* r=Copy(hWid, x, List); //to store the residue
+
+  double Bw=3.0*B;
+  while (i<I)
+  {
+    if ((i>0 && f[i]-f[i-1]>Bw) || i==I-1)
+    {
+      if (i==I-1) i++;
+
+      //process frequencies from ist to i-1
+      if (i-1==ist) //one sinusoid
+      {
+        double fb=f[ist];
+        cdouble* w=Window(0, fb, Wid, M, c, 0, hWid-1);
+        for (int k=0; k<hWid; k++) w[k].rotate(ph[ist]);
+        double ip=Inner(2*hWid, (double*)x, (double*)w);
+        a[ist]=ip*iH2;
+        MultiAdd(hWid, r, r, w, -a[ist]);
+        delete[] w;
+      }
+      else
+      {
+        int N=i-ist;
+        cdouble** Allocate2L(cdouble, N, hWid, wt, List);
+        for (int n=0; n<N; n++)
+        {
+          Window(wt[n], f[ist+n], Wid, M, c, 0, hWid-1);
+          for (int k=0; k<hWid; k++) wt[n][k].rotate(ph[ist+n]);
+        }
+        double* whxr=MultiplyXy(N, hWid*2, (double**)wt, (double*)x, List); //w*'x=(wt*)x
+        double** whwr=MultiplyXXt(N, hWid*2, (double**)wt, List);
+        GECP(N, &a[ist], whwr, whxr); //solving complex linear system (w*'w)a=w*'x
+        for (int n=0; n<N; n++) MultiAdd(hWid, r, r, wt[n], -a[ist+n]);
+      }
+      ist=i;
+    }
+    i++;
+  }
+  double result=Inner(hWid, r, r).x;
+  delete List;
+  return result;
+}//IPMulti_Direct
+
+/*
+  function IPMulti_GS: LSE estimation of multiple sinusoids given frequencies AND PHASES (Gram-Schmidt method)
+
+  In: x[Wid]: spectrum
+      f[I], ph[I]: frequencies and phase angles.
+      B: spectral truncation, in bins; sinusoids over 3B bins apart are regarded non-interfering
+      M, c[], iH2: cosine-family window specification parameters
+  Out: a[I]: amplitudes
+
+  Returns square norm of the residue.
+*/
+double IPMulti_GS(int I, double* f, double* ph, double* a, cdouble* x, int Wid, int M, double* c, double iH2, int B, double** L, double** Q)
+{
+  MList* List=new MList;
+  int i=0, ist=0, hWid=Wid/2;
+  cdouble* r=Copy(hWid, x, List); //to store the residue
+  double Bw=3.0*B;
+  while (i<I)
+  {
+    if ((i>0 && f[i]-f[i-1]>Bw) || i==I-1)
+    {
+      if (i==I-1) i++;
+
+      //process frequencies from ist to i-1
+      if (i-1==ist) //one sinusoid
+      {
+        double fb=f[ist];
+        cdouble* w=Window(0, fb, Wid, M, c, 0, hWid-1);
+        for (int k=0; k<hWid; k++) w[k].rotate(ph[ist]);
+        double ip=Inner(2*hWid, (double*)x, (double*)w);
+        a[ist]=ip*iH2;
+        MultiAdd(hWid, r, r, w, -a[ist]);
+        delete[] w;
+      }
+      else
+      {
+        int N=i-ist;
+        cdouble** Allocate2L(cdouble, N, hWid, wt, List);
+        Alloc2L(N, N, L, List); Alloc2L(N, hWid*2, Q, List);
+        for (int n=0; n<N; n++)
+        {
+          Window(wt[n], f[ist+n], Wid, M, c, 0, hWid-1);
+          for (int k=0; k<hWid; k++) wt[n][k].rotate(ph[ist+n]);
+        }
+        LQ_GS(N, hWid*2, (double**)wt, L, Q);
+        double* atl=MultiplyxYt(N, hWid*2, (double*)x, Q, List);
+        GExL(N, &a[ist], L, atl);
+        for (int n=0; n<N; n++) MultiAdd(hWid, r, r, wt[n], -a[ist+n]);
+      }
+      ist=i;
+    }
+    i++;
+  }
+  double result=Inner(hWid, r, r).x;
+  delete List;
+	return result;
+}//IPMulti_GS
+
+/*
+  function IPMulti: LSE estimation of I sinusoids given frequency and phase and J sinusoids given
+  frequency only
+
+  In: x[Wid]: spectrum
+      f[I+J], ph[I]: frequencies and phase angles
+      M, c[], iH2: cosine-family window specification parameters
+  Out: a[I+J]: amplitudes
+       ph[I:I+J-1]: phase angles not given on start
+       wt[I+2J][hWid], Q[I+2J][hWid], L[I+2J][I+2J]: internal w matrix and its LQ factorization, optional
+
+  Returns the residue vector, newly created and registered to RetList, if specified. On start a[] should
+  have valid storage no less than I+2J.
+*/
+cdouble* IPMulti(int I, int J, double* f, double* ph, double* a, cdouble* x, int Wid, int M, double* c, cdouble** wt, cdouble** Q, double** L, MList* RetList)
+{
+  MList* List=new MList;
+  int hWid=Wid/2;
+  cdouble* r=Copy(hWid, x, RetList); //to store the residue
+  if (!wt){Allocate2L(cdouble, I+J*2, hWid, wt, List);}
+  if (!Q){Allocate2L(cdouble, I+J*2, hWid, Q, List);}
+  if (!L){Allocate2L(double, I+J*2, I+J*2, L, List);}
+  memset(wt[0], 0, sizeof(cdouble)*(I+J*2)*hWid);
+  memset(Q[0], 0, sizeof(cdouble)*(I+J*2)*hWid);
+  memset(L[0], 0, sizeof(double)*(I+J*2)*(I+J*2));
+
+  //*The direct form
+  for (int i=0; i<I; i++)
+  {
+    Window(wt[i], f[i], Wid, M, c, 0, hWid-1);
+    for (int k=0; k<hWid; k++) wt[i][k].rotate(ph[i]);
+  }
+  for (int j=0; j<J; j++)
+  {
+    cdouble *w1=wt[I+j*2], *w2=wt[I+j*2+1];
+    Window(w1, f[I+j], Wid, M, c, 0, hWid-1);
+    for (int k=0; k<hWid; k++) w2[k].y=w1[k].x, w2[k].x=-w1[k].y;
+  }
+
+  LQ_GS(I+J*2, hWid*2, (double**)wt, L, (double**)Q);
+  double *atl=MultiplyxYt(I+J*2, hWid*2, (double*)x, (double**)Q, List);
+  GExL(I+J*2, a, L, atl);
+  
+  for (int i=0; i<I+J*2; i++) MultiAdd(hWid, r, r, wt[i], -a[i]);
+  for (int j=0; j<J; j++)
+  {
+    double xx=a[I+j*2], yy=a[I+j*2+1];
+    a[I+j]=sqrt(xx*xx+yy*yy);
+    ph[I+j]=atan2(yy, xx);
+  }
+  delete List;
+  return r;
+}//IPMulti
+
+//---------------------------------------------------------------------------
+/*
+    Routines for estimation two sinusoids with 1 fixed and 1 flexible frequency
+
+    Further reading: "LSE estimation for 2 sinusoids with 1 at a fixed frequency.pdf"
+*/
+
+/*
+  function WindowDuo: calcualtes the square norm of the inner product between windowed spectra of two
+  sinusoids at frequencies f1 and f2, df=f1-f2.
+
+  In: df: frequency difference, in bins
+      N: DFT size
+      M, d[]: cosine-family window specification parameters (see "further reading").
+  Out: w[0], the inner product, optional
+
+  Returns square norm of the inner product.
+*/
+double WindowDuo(double df, int N, double* d, int M, cdouble* w)
+{
+	double wr=0, wi=0;
+	for (int m=-2*M; m<=2*M; m++)
+	{
+		double ang=df+m, Omg=ang*M_PI, omg=Omg/N;
+		double si=sin(omg), co=cos(omg), sinn=sin(Omg);
+		double sa=(ang==0)?N:(sinn/si);
+		double dm; if (m<0) dm=d[-m]; else dm=d[m];
+		wr+=dm*sa*co, wi+=-dm*sinn;
+	}
+	wr*=N, wi*=N;
+	if (w) w->x=wr, w->y=wi;
+	double result=wr*wr+wi*wi;
+	return result;
+}//WindowDuo
+
+/*
+  function ddWindowDuo: calcualtes the square norm of the inner product between windowed spectra of two
+  sinusoids at frequencies f1 and f2, df=f1-f2, with its 1st and 2nd derivatives
+
+  In: df: frequency difference, in bins
+      N: DFT size
+      M, d[]: cosine-family window specification parameters (see "further reading" for d[]).
+  Out: w[0], the inner product, optional
+       window, dwindow: square norm and its derivative, of the inner product
+
+  Returns 2nd derivative of the square norm of the inner product.
+*/
+double ddWindowDuo(double df, int N, double* d, int M, double& dwindow, double& window, cdouble* w)
+{
+	double wr=0, wi=0, dwr=0, dwi=0, ddwr=0, ddwi=0, PI_N=M_PI/N, PIPI_N=PI_N*M_PI, PIPI=M_PI*M_PI;
+	for (int m=-2*M; m<=2*M; m++)
+	{
+		double ang=df+m, Omg=ang*M_PI, omg=Omg/N;
+		double si=sin(omg), co=cos(omg), sinn=sin(Omg), cosn=cos(Omg);
+		double sa=(ang==0)?N:(sinn/si), dsa=dsincd_unn(ang, N), ddsa=ddsincd_unn(ang, N);
+		double dm; if (m<0) dm=d[-m]; else dm=d[m];
+		wr+=dm*sa*co, wi+=-dm*sinn;
+		dwr+=dm*(dsa*co-PI_N*sinn), dwi+=-dm*M_PI*cosn;
+		ddwr+=dm*(ddsa*co-PI_N*dsa*si-PIPI_N*cosn), ddwi+=dm*PIPI*sinn;
+	}
+  wr*=N, wi*=N, dwr*=N, dwi*=N, ddwr*=N, ddwi*=N;
+  window=wr*wr+wi*wi;
+  dwindow=2*(wr*dwr+wi*dwi);
+  if (w) w->x=wr, w->y=wi;
+	double ddwindow=2*(wr*ddwr+dwr*dwr+wi*ddwi+dwi*dwi);
+  return ddwindow;
+}//ddWindowDuo
+
+/*
+  function sIPWindowDuo: calculates the square norm of the orthogonal projection of a windowed spectrum
+  onto the linear span of the windowed spectra of two sinusoids at reference frequencies f1 and f2.
+
+  In: x[N]: spectrum
+      f1, f2: reference frequencies.
+      M, c[], d[], iH2: cosine-family window specification parameters.
+      K1, K2: spectrum truncation range, i.e. bins outside [K1, K2] are ignored.
+  Out: lmd1, lmd2: projection coefficients, interpreted as actual amplitude-phase factors
+
+  Returns the square norm of the orthogonal projection.
+*/
+double sIPWindowDuo(double f1, double f2, cdouble* x, int N, double* c, double* d, int M, double iH2, int K1, int K2, cdouble& lmd1, cdouble& lmd2)
+{
+	int K=K2-K1+1;
+  cdouble xw1=0, *lx=&x[K1], *w1=new cdouble[K*2], *r1=&w1[K];
+  Window(w1, f1, N, M, c, K1, K2);
+  double w1w1=0;
+  for (int k=0; k<K; k++) xw1+=(lx[k]^w1[k]), w1w1+=~w1[k]; cdouble mu1=xw1/w1w1;
+  for (int k=0; k<K; k++) r1[k]=lx[k]-mu1*w1[k];
+	Window(w1, f2, N, M, c, K1, K2);
+  cdouble r1w2=0, w12; for (int k=0; k<K; k++) r1w2+=(r1[k]^w1[k]);
+  double w=WindowDuo(f1-f2, N, d, M, &w12);
+  double v=1.0/iH2-w*iH2;
+  double result=~xw1/w1w1+~r1w2/v;
+	cdouble mu2=r1w2/v;
+	lmd2=mu2; lmd1=mu1-(mu2^w12)*iH2;
+  delete[] w1;
+  return result;
+}//sIPWindowDuo
+//wrapper function
+double sIPWindowDuo(double f2, void* params)
+{
+	struct l_ip {int N; int k1; int k2; double* c; double* d; int M; double iH2; cdouble* x; double f1; double dipwindow; double ipwindow;} *p=(l_ip *)params;
+	cdouble r1, r2;
+	return sIPWindowDuo(p->f1, f2, p->x, p->N, p->c, p->d, p->M, p->iH2, p->k1, p->k2, r1, r2);
+}//sIPWindowDuo
+
+/*
+  function ddsIPWindowDuo: calculates the square norm, and its 1st and 2nd derivatives against f2,, of
+  the orthogonal projection of a windowed spectrum onto the linear span of the windowed spectra of two
+  sinusoids at reference frequencies f1 and f2.
+
+  In: x[N]: spectrum
+      f1, f2: reference frequencies.
+      M, c[], d[], iH2: cosine-family window specification parameters.
+      K1, K2: spectrum truncation range, i.e. bins outside [K1, K2] are ignored.
+
+  Out: lmd1, lmd2: projection coefficients, interpreted as actual amplitude-phase factors
+       ddsip[3]: the 2nd, 1st and 0th derivatives (against f2) of the square norm.
+
+  No return value.
+*/
+void ddsIPWindowDuo(double* ddsip2, double f1, double f2, cdouble* x, int N, double* c, double* d, int M, double iH2, int K1, int K2, cdouble& lmd1, cdouble& lmd2)
+{
+  int K=K2-K1+1;
+	cdouble xw1=0, *lx=&x[K1], *w1=new cdouble[K*2], *r1=&w1[K];
+  Window(w1, f1, N, M, c, K1, K2);
+  double w1w1=0;
+  for (int k=0; k<K; k++) xw1+=(lx[k]^w1[k]), w1w1+=~w1[k]; cdouble mu1=xw1/w1w1;
+  for (int k=0; k<K; k++) r1[k]=lx[k]-mu1*w1[k];
+
+  cdouble r1w2, w12;
+  double u, du, ddu=ddsIPWindow_unn(f2, &r1[-K1], N, M, c, K1, K2, du, u, &r1w2);
+	double w, dw, ddw=ddWindowDuo(f1-f2, N, d, M, dw, w, &w12); dw=-dw;
+  double v=1.0/iH2-w*iH2, dv=-iH2*dw, ddv=-iH2*ddw;
+	double iv=1.0/v;//, div=-dv*iv*iv, ddiv=(2*dv*dv-v*ddv)*iv*iv*iv;
+
+  ddsip2[2]=~xw1/w1w1+u*iv;
+  ddsip2[1]=iv*(du-iv*u*dv);
+  ddsip2[0]=iv*(ddu-iv*(u*ddv+2*du*dv-2*iv*u*dv*dv));
+
+  cdouble mu2=r1w2*iv;
+	lmd2=mu2; lmd1=mu1-(mu2^w12)*iH2;
+
+  delete[] w1;
+}//ddsIPWindowDuo
+//wrapper function
+double ddsIPWindowDuo(double f2, void* params)
+{
+	struct l_ip {int N; int k1; int k2; double* c; double* d; int M; double iH2; cdouble* x; double f1; double dipwindow; double ipwindow;} *p=(l_ip *)params;
+  double ddsip2[3]; cdouble r1, r2;
+  ddsIPWindowDuo(ddsip2, p->f1, f2, p->x, p->N, p->c, p->d, p->M, p->iH2, p->k1, p->k2, r1, r2);
+  p->dipwindow=ddsip2[1], p->ipwindow=ddsip2[2];
+  return ddsip2[0];
+}//ddsIPWindowDuo
+
+/*
+  function LSEDuo: least-square estimation of two sinusoids of which one has a fixed frequency
+
+  In: x[N]: the windowed spectrum
+      f1: the fixed frequency
+      f2: initial value of the flexible frequency
+      fmin, fmax: search range for f2, the flexible frequency
+      B: spectral truncation half width
+      M, c[], d[], iH2:
+      epf: frequency error tolerance
+  Out: f2: frequency estimate
+       lmd1, lmd2: amplitude-phase factor estimates
+  Returns 1 if managed to find a good f2, 0 if not, upon which the initial f2 is used for estimating
+
+  amplitudes and phase angles.
+*/
+int LSEDuo(double& f2, double fmin, double fmax, double f1, cdouble* x, int N, double B, double* c, double* d, int M, double iH2, cdouble& r1, cdouble &r2, double epf)
+{
+  int result=0;
+  double inp=f2;
+  int k1=ceil(inp-B); if (k1<0) k1=0;
+  int k2=floor(inp+B); if (k2>=N/2) k2=N/2-1;
+  struct l_hx {int N; int k1; int k2; double* c; double* d; int M; double iH2; cdouble* x; double f1; double dipwindow; double ipwindow;} p={N, k1, k2, c, d, M, iH2, x, f1, 0, 0};
+  int dfshift=int(&((l_hx*)0)->dipwindow);// fshift=int(&((l_hx*)0)->ipwindow);
+
+  double tmp=Newton(f2, ddsIPWindowDuo, &p, dfshift, epf, 100, 1e-256, fmin, fmax);
+  if (tmp!=-1 && f2>fmin && f2<fmax) result=1;
+  else
+  {
+    Search1DmaxEx(f2, &p, sIPWindowDuo, fmin, fmax, NULL, epf);
+    if (f2<=fmin || f2>=fmax) f2=inp;
+    else result=1;
+  }
+  sIPWindowDuo(f1, f2, x, N, c, d, M, iH2, k1, k2, r1, r2);
+  return result;
+}//LSEDuo
+
+//---------------------------------------------------------------------------
+/*
+    Time-frequency reassignment sinusoid estimation routines.
+
+    Further reading: A. R?bel, ¡°Estimating partial frequency and frequency slope using reassignment
+    operators,¡± in Proc. ICMC¡¯02. G?teborg. 2002.
+*/
+
+/*
+  function CDFTW: single-frequency windowed DTFT, centre-aligned
+
+  In: data[Wid]: waveform data x
+      win[Wid+1]: window function
+      k: frequency, in bins, where bin=1/Wid
+  Out: X: DTFT of xw at frequency k bins
+
+  No return value.
+*/
+void CDFTW(cdouble& X, double k, int Wid, cdouble* data, double* win)
+{
+  X=0;
+  int hWid=Wid/2;
+  for (int i=0; i<Wid; i++)
+  {
+    cdouble tmp=data[i]*win[Wid-i];
+    double ph=-2*M_PI*(i-hWid)*k/Wid;
+    tmp.rotate(ph);
+    X+=tmp;
+  }
+}//CDFTW
+
+/*
+  function CuDFTW: single-frequency windowed DTFT of t*data[t], centre-aligned
+
+  In: data[Wid]: waveform data x
+      wid[Wid+1]: window function
+      k: frequency, in bins
+  Out: X: DTFT of txw at frequency k bins
+
+  No return value.
+*/
+void CuDFTW(cdouble& X, int k, int Wid, cdouble* data, double* win)
+{
+  X=0;
+  int hWid=Wid/2;
+  for (int i=0; i<Wid; i++)
+	{
+		double tw=((i-hWid)*win[Wid-i]);
+		cdouble tmp=data[i]*tw;
+    double ph=-2*M_PI*(i-hWid)*k/Wid;
+    tmp.rotate(ph);
+		X+=tmp;
+  }
+}//CuDFTW
+
+/*
+  function TFReas: time-frequency reassignment
+
+  In: data[Wid]: waveform data
+      win[Wid+1], dwin[Wid+1], ddwin[Wid+1]: window function and its derivatives
+      f, t: initial digital frequency and time
+  Out: f, t: reassigned digital frequency and time
+       fslope: estimate of frequency derivative
+       plogaslope[0]: estimate of the derivative of logarithmic amplitude, optional
+
+  No return value.
+*/
+void TFReas(double& f, double& t, double& fslope, int Wid, cdouble* data, double* win, double* dwin, double* ddwin, double* plogaslope)
+{
+	int fi=floor(f*Wid+0.5);
+
+	cdouble x, xt, xw;
+  CDFTW(x, fi, Wid, data, win);
+  CuDFTW(xw, fi, Wid, data, win); xt.x=xw.y; xw.y=-xw.x; xw.x=xt.x;
+  CDFTW(xt, fi, Wid, data, dwin);
+  double px=~x;
+  t=t-(xw.y*x.x-xw.x*x.y)/px;
+	f=1.0*fi/Wid+(xt.y*x.x-xt.x*x.y)/px/(2*M_PI);
+	if (plogaslope) plogaslope[0]=-(xt.x*x.x+xt.y*x.y)/px;
+  cdouble xtt, xtw;
+  CuDFTW(xtw, fi, Wid, data, dwin); xtt.x=xtw.y; xtw.y=-xtw.x; xtw.x=xtt.x;
+  CDFTW(xtt, fi, Wid, data, ddwin);
+  double dtdt=-(xtw.y*x.x-xtw.x*x.y)/px+((xt.y*x.x-xt.x*x.y)*(xw.x*x.x+xw.y*x.y)+(xt.x*x.x+xt.y*x.y)*(xw.y*x.x-xw.x*x.y))/px/px,
+         dwdt=(xtt.y*x.x-xtt.x*x.y)/px-2*(xt.x*x.x+xt.y*x.y)*(xt.y*x.x-xt.x*x.y)/px/px;
+  if (dtdt!=0) fslope=dwdt/dtdt/(2*M_PI);
+  else fslope=0;
+} //TFReas*/
+
+/*
+  function TFReas: sinusoid estimation using reassignment method
+
+  In: data[Wid]: waveform data
+      w[Wid+1], dw[Wid+1], ddw[Wid+1]: window function and its derivatives
+      win[Wid]: window function used for estimating amplitude and phase by projection onto a chirp
+      t: time for which the parameters are estimated
+      f: initial frequency at t
+  Out: f, a, ph: digital frequency, amplitude and phase angle estimated at t
+       fslope: frequency derivative estimate
+
+  No return value.
+*/
+void TFReas(double& f, double t, double& a, double& ph, double& fslope, int Wid, cdouble* data, double* w, double* dw, double* ddw, double* win)
+{
+	double localt=t, logaslope;
+	TFReas(f, localt, fslope, Wid, data, w, dw, ddw, &logaslope);
+
+	if (logaslope*Wid>6) logaslope=6.0/Wid;
+	else if (logaslope*Wid<-6) logaslope=-6.0/Wid;
+
+	f=f+fslope*(t-localt); //obtain frequency estimate at t
+
+	cdouble x=0;
+	if (win==0)
+	{
+		for (int n=0; n<Wid; n++)
+		{
+			double ni=n-t;
+			cdouble tmp=data[n];
+			double p=-2*M_PI*(f+0.5*fslope*ni)*ni;
+			tmp.rotate(p);
+			x+=tmp;
+		}
+		a=abs(x)/Wid;
+	}
+	else
+	{
+		double sumwin=0;
+		for (int n=0; n<Wid; n++)
+		{
+			double ni=n-t;
+			cdouble tmp=data[n]*win[n];
+			double p=-2*M_PI*(f+0.5*fslope*ni)*ni;
+			tmp.rotate(p);
+			x+=tmp; sumwin+=win[n];
+		}
+		a=abs(x)/sumwin;
+	}
+	ph=arg(x);
+}//TFReas
+
+//---------------------------------------------------------------------------
+/*
+    Routines for additive and multiplicative reestimation of sinusoids.
+
+    Further reading: Wen X. and M. Sandler, "Additive and multiplicative reestimation schemes
+    for the sinusoid modeling of audio," in Proc. EUSIPCO'09, Glasgow, 2009.
+*/
+
+/*
+  function AdditiveUpdate: additive reestimation of time-varying sinusoid
+
+  In: x[Count]: waveform data
+      Wid, Offst: frame size and hop
+      fs[Count], as[Count], phs[Count]: initial estimate of sinusoid parameters
+      das[Count]: initial estimate of amplitude derivative
+      BasicAnalyzer: pointer to a sinusoid analyzer
+      LogA: indicates if amplitudes are interpolated at cubic spline or exponential cubic spline
+  Out: fs[Count], as[Count], phs[Count], das[Count]: estimates after additive update
+
+  No return value.
+*/
+void AdditiveUpdate(double* fs, double* as, double* phs, double* das, cdouble* x, int Count, int Wid, int Offst, TBasicAnalyzer BasicAnalyzer, int reserved, bool LogA)
+{
+  int HWid=Wid/2, Fr=(Count-Wid)/Offst+1;
+
+	for (int fr=0; fr<Fr; fr++)
+	{
+		int i=HWid+Offst*fr;
+    if (fs[i]<0 || fs[i]>0.5){}
+	}
+
+	cdouble *y=new cdouble[Count];
+	double *lf=new double[Count*4], *la=&lf[Count], *lp=&lf[Count*2], *lda=&lf[Count*3];
+
+	__int16* ref=new __int16[Count];
+	for (int i=0; i<Count; i++) y[i]=x[i].x-as[i]*cos(phs[i]), ref[i]=floor(fs[i]*Wid+0.5);
+	memcpy(lf, fs, sizeof(double)*Count);
+	BasicAnalyzer(lf, la, lp, lda, y, Count, Wid, Offst, ref, reserved, LogA);
+
+  //merge and interpolate
+  double *fa=new double[Fr*12], *fb=&fa[Fr], *fc=&fa[Fr*2], *fd=&fa[Fr*3],
+       *aa=&fa[Fr*4], *ab=&aa[Fr], *ac=&aa[Fr*2], *ad=&aa[Fr*3],
+       *xs=&fa[Fr*8], *ffr=&xs[Fr], *afr=&xs[Fr*2], *pfr=&xs[Fr*3];
+  for (int fr=0; fr<Fr; fr++)
+  {
+		int i=HWid+Offst*fr;
+    double a=as[i], b=la[i], fai=phs[i], thet=lp[i], f=fs[i], g=lf[i], delt=fai-thet, da=das[i], db=lda[i];
+		xs[fr]=i;
+		if (fabs(f-g)*Wid>1)
+    {
+      afr[fr]=a, pfr[fr]=fai, ffr[fr]=f;
+    }
+    else
+    {
+      double rr=a*cos(fai)+b*cos(thet);
+      double ii=a*sin(fai)+b*sin(thet);
+			ffr[fr]=(a*f*(a+b*cos(delt))+b*g*(b+a*cos(delt))+(da*b-a*db)*sin(delt)/(2*M_PI))/(a*a+b*b+2*a*b*cos(delt));
+      afr[fr]=sqrt(rr*rr+ii*ii);
+			pfr[fr]=atan2(ii, rr);
+		}
+		if (LogA) afr[fr]=log(afr[fr]);
+	}
+	CubicSpline(Fr-1, fa, fb, fc, fd, xs, ffr, 1, 1);
+	CubicSpline(Fr-1, aa, ab, ac, ad, xs, afr, 1, 1);
+	for (int fr=0; fr<Fr-1; fr++) Sinusoid(&fs[int(xs[fr])], &as[int(xs[fr])], &phs[int(xs[fr])], &das[int(xs[fr])], 0, Offst, aa[fr], ab[fr], ac[fr], ad[fr], fa[fr], fb[fr], fc[fr], fd[fr], pfr[fr], pfr[fr+1], LogA);
+	Sinusoid(&fs[int(xs[0])], &as[int(xs[0])], &phs[int(xs[0])], &das[int(xs[0])], -HWid, 0, aa[0], ab[0], ac[0], ad[0], fa[0], fb[0], fc[0], fd[0], pfr[0], pfr[1], LogA);
+	Sinusoid(&fs[int(xs[Fr-2])], &as[int(xs[Fr-2])], &phs[int(xs[Fr-2])], &das[int(xs[Fr-2])], Offst, Offst+HWid, aa[Fr-2], ab[Fr-2], ac[Fr-2], ad[Fr-2], fa[Fr-2], fb[Fr-2], fc[Fr-2], fd[Fr-2], pfr[Fr-2], pfr[Fr-1], LogA);
+	delete[] fa;  //*/
+	/*
+  for (int i=0; i<Count; i++)
+  {
+    double rr=as[i]*cos(phs[i])+la[i]*cos(lp[i]);
+    double ii=as[i]*sin(phs[i])+la[i]*sin(lp[i]);
+		as[i]=sqrt(rr*rr+ii*ii);
+    phs[i]=atan2(ii, rr);
+	}         //*/
+	for (int fr=0; fr<Fr; fr++)
+	{
+		int i=HWid+Offst*fr;
+    if (fs[i]<0 || fs[i]>0.5){}
+	}
+	delete[] y; delete[] lf; delete[] ref;
+}//AdditiveUpdate
+
+/*
+  function AdditiveAnalyzer: sinusoid analyzer with one additive update
+
+  In: x[Count]: waveform data
+      Wid, Offst: frame size and hop size
+      BasicAnalyzer: pointer to a sinusoid analyzer
+      ref[Count]: reference frequencies, in bins, used by BasicAnalyzer
+      BasicAnalyzer: pointer to a sinusoid analyzer
+      LogA: indicates if amplitudes are interpolated at cubic spline or exponential cubic spline
+  Out: fs[Count], as[Count], phs[Count]: sinusoid parameter estimates
+       das[Count]: estimate of amplitude derivative
+
+  No return value.
+*/
+void AdditiveAnalyzer(double* fs, double* as, double* phs, double* das, cdouble* x, int Count, int Wid, int Offst, __int16* ref, TBasicAnalyzer BasicAnalyzer, int reserved, bool LogA)
+{
+	BasicAnalyzer(fs, as, phs, das, x, Count, Wid, Offst, ref, reserved, LogA);
+	AdditiveUpdate(fs, as, phs, das, x, Count, Wid, Offst, BasicAnalyzer, reserved, LogA);
+}//AdditiveAnalyzer
+
+/*
+  function MultiplicativeUpdate: multiplicative reestimation of time-varying sinusoid
+
+  In: x[Count]: waveform data
+      Wid, Offst: frame size and hop
+      fs[Count], as[Count], phs[Count]: initial estimate of sinusoid parameters
+      das[Count]: initial estimate of amplitude derivative
+      BasicAnalyzer: pointer to a sinusoid analyzer
+      LogA: indicates if amplitudes are interpolated at cubic spline or exponential cubic spline
+  Out: fs[Count], as[Count], phs[Count], das[Count]: estimates after additive update
+
+  No return value.
+*/
+void MultiplicativeUpdate(double* fs, double* as, double* phs, double* das, cdouble* x, int Count, int Wid, int Offst, TBasicAnalyzer BasicAnalyzer, int reserved, bool LogA)
+{
+  int HWid=Wid/2;
+  cdouble *y=new cdouble[Count];
+  double *lf=new double[Count*8], *la=&lf[Count], *lp=&lf[Count*2], *lda=&lf[Count*3],
+         *lf2=&lf[Count*4], *la2=&lf2[Count], *lp2=&lf2[Count*2], *lda2=&lf2[Count*3];
+	__int16 *lref=new __int16[Count];
+
+	for (int i=0; i<Count; i++) y[i]=x[i]*(cdouble(1.0).rotate(-phs[i]+i*0.15*2*M_PI)),
+														lref[i]=0.15*Wid;
+	BasicAnalyzer(lf, la, lp, lda, y, Count, Wid, Offst, lref, reserved, LogA);
+	for (int i=0; i<Count; i++) y[i]=y[i]*(cdouble(1.0/la[i]).rotate(-lp[i]+i*0.15*2*M_PI)), lref[i]=0.15*Wid;
+	BasicAnalyzer(lf2, la2, lp2, lda2, y, Count, Wid, Offst, lref, reserved, LogA);
+
+		/*
+		for (int i=0; i<Count; i++)
+		{
+			as[i]=la[i]*la2[i];
+			phs[i]=phs[i]+lp[i]+lp2[i]-0.3*2*M_PI*i;
+      fs[i]=fs[i]+lf[i]+lf2[i]-0.3;
+		}         //*/
+
+	//merge
+	int Fr=(Count-Wid)/Offst+1;
+	double *fa=new double[Fr*12], *fb=&fa[Fr], *fc=&fa[Fr*2], *fd=&fa[Fr*3],
+				 *aa=&fa[Fr*4], *ab=&aa[Fr], *ac=&aa[Fr*2], *ad=&aa[Fr*3],
+				 *xs=&fa[Fr*8], *ffr=&xs[Fr], *afr=&xs[Fr*2], *pfr=&xs[Fr*3];
+	for (int fr=0; fr<Fr; fr++)
+	{
+		int i=HWid+Offst*fr;
+		xs[fr]=i;
+		afr[fr]=la[i]*la2[i];
+		if (LogA) afr[fr]=log(afr[fr]);
+		ffr[fr]=fs[i]+lf[i]-0.15+lf2[i]-0.15;
+		pfr[fr]=phs[i]+lp[i]+lp2[i]-0.3*i*2*M_PI;
+	}
+	CubicSpline(Fr-1, fa, fb, fc, fd, xs, ffr, 1, 1);
+	CubicSpline(Fr-1, aa, ab, ac, ad, xs, afr, 1, 1);
+	for (int fr=0; fr<Fr-1; fr++) Sinusoid(&fs[int(xs[fr])], &as[int(xs[fr])], &phs[int(xs[fr])], &das[int(xs[fr])], 0, Offst, aa[fr], ab[fr], ac[fr], ad[fr], fa[fr], fb[fr], fc[fr], fd[fr], pfr[fr], pfr[fr+1], LogA);
+	Sinusoid(&fs[int(xs[0])], &as[int(xs[0])], &phs[int(xs[0])], &das[int(xs[0])], -HWid, 0, aa[0], ab[0], ac[0], ad[0], fa[0], fb[0], fc[0], fd[0], pfr[0], pfr[1], LogA);
+	Sinusoid(&fs[int(xs[Fr-2])], &as[int(xs[Fr-2])], &phs[int(xs[Fr-2])], &das[int(xs[Fr-2])], Offst, Offst+HWid, aa[Fr-2], ab[Fr-2], ac[Fr-2], ad[Fr-2], fa[Fr-2], fb[Fr-2], fc[Fr-2], fd[Fr-2], pfr[Fr-2], pfr[Fr-1], LogA);
+	delete[] fa;  //*/
+
+	for (int fr=0; fr<Fr; fr++)
+	{
+		int i=HWid+Offst*fr;
+    if (fs[i]<0 || fs[i]>0.5){}
+	}
+
+	delete[] y; delete[] lf; delete[] lref;
+}//MultiplicativeUpdate
+
+/*
+  function MultiplicativeAnalyzer: sinusoid analyzer with one multiplicative update
+
+  In: x[Count]: waveform data
+      Wid, Offst: frame size and hop size
+      BasicAnalyzer: pointer to a sinusoid analyzer
+      ref[Count]: reference frequencies, in bins, used by BasicAnalyzer
+      BasicAnalyzer: pointer to a sinusoid analyzer
+      LogA: indicates if amplitudes are interpolated at cubic spline or exponential cubic spline
+  Out: fs[Count], as[Count], phs[Count]: sinusoid parameter estimates
+       das[Count]: estimate of amplitude derivative
+
+  No return value.
+*/
+void MultiplicativeAnalyzer(double* fs, double* as, double* phs, double* das, cdouble* x, int Count, int Wid, int Offst, __int16* ref, TBasicAnalyzer BasicAnalyzer, int reserved, bool LogA)
+{
+	BasicAnalyzer(fs, as, phs, das, x, Count, Wid, Offst, ref, reserved, LogA);
+	MultiplicativeUpdate(fs, as, phs, das, x, Count, Wid, Offst, BasicAnalyzer, reserved);
+}//MultiplicativeAnalyzer
+
+/*
+  This is an earlier version of the multiplicative method without using a user-provided BasicAnalyzer.
+  This updates the sinusoid estimates at the selected consecutive FRAMES of x. Only frequency modulation
+  is included in the multiplier. The first frame (0) is centred at x[Wid/2]. fs, as, and phs are based
+  on frames rather than samples. Updates include frame frst, but not frame fren.
+*/
+void MultiplicativeUpdateF(double* fs, double* as, double* phs, __int16* x, int Fr, int frst, int fren, int Wid, int Offst)
+{
+  int HWid=Wid/2;
+
+  double *fa=new double[Fr*12], *fb=&fa[Fr], *fc=&fa[Fr*2], *fd=&fa[Fr*3],
+         *xs=&fa[Fr*8];
+  for (int fr=0; fr<Fr; fr++) xs[fr]=HWid+Offst*fr;
+  CubicSpline(Fr-1, fa, fb, fc, fd, xs, fs, 1, 1);
+
+  int dst=Offst*frst, den=Offst*(fren-1)+Wid, dcount=den-dst;
+  double *f=new double[dcount*2], *ph=&f[dcount];
+  for (int fr=frst; fr<fren-1; fr++) Sinusoid(&f[int(xs[fr])-dst], &ph[int(xs[fr])-dst], 0, Offst, fa[fr], fb[fr], fc[fr], fd[fr], phs[fr], phs[fr+1]);
+  if (frst==0) Sinusoid(&f[int(xs[0])-dst], &ph[int(xs[0])-dst], -HWid, 0, fa[0], fb[0], fc[0], fd[0], phs[0], phs[1]);
+  else Sinusoid(&f[int(xs[frst-1])-dst], &ph[int(xs[frst-1])-dst], 0, Offst, fa[frst-1], fb[frst-1], fc[frst-1], fd[frst-1], phs[frst-1], phs[frst]);
+  if (fren==Fr) Sinusoid(&f[int(xs[fren-2])-dst], &ph[int(xs[fren-2])-dst], Offst, Offst+HWid, fa[fren-2], fb[fren-2], fc[fren-2], fd[fren-2], phs[fren-2], phs[fren-1]);
+  else Sinusoid(&f[int(xs[fren-1])-dst], &ph[int(xs[fren-1])-dst], 0, Offst, fa[fren-1], fb[fren-1], fc[fren-1], fd[fren-1], phs[fren-1], phs[fren]);
+
+  cdouble* y=new cdouble[Wid];
+  AllocateFFTBuffer(Wid, Amp, W, X);
+  double* win=NewWindow(wtHann, Wid);
+  int M; double c[10], iH2; windowspec(wtHann, Wid, &M, c, &iH2);
+  for (int fr=frst; fr<fren; fr++)
+  {
+    __int16* lx=&x[Offst*fr];
+    double* lph=&ph[Offst*(fr-frst)];
+    for (int i=0; i<Wid; i++) y[i]=cdouble(lx[i]).rotate(-lph[i]+i*0.15*2*M_PI);
+    CFFTCW(y, win, Amp, 0, log2(Wid), W, X);
+    int pf=0.15*Wid, mpf=pf;
+    for (int k=pf-4; k<=pf+4; k++) if (Amp[k]>Amp[mpf]) mpf=k;
+    if (mpf>pf-4 && mpf<pf+4) pf=mpf;
+    double lfs=pf, lphs;
+    LSESinusoid(lfs, pf-3, pf+3, X, Wid, 3, M, c, iH2, as[fr], lphs, 1e-3);
+    fs[fr]=fs[fr]+lfs/Wid-0.15;
+    phs[fr]+=lphs-0.15*Wid*M_PI;
+      as[fr]*=2;
+  }
+
+  delete[] y;
+  delete[] f;
+  delete[] win;
+  delete[] fa;
+  FreeFFTBuffer(Amp);
+}//MultiplicativeUpdateF
+
+//---------------------------------------------------------------------------
+/*
+    Earlier reestimation method routines.
+
+    Further reading: Wen X. and M. Sandler, "Evaluating parameters of time-varying
+    sinusoids by demodulation," in Proc. DAFx'08, Espoo, 2008.
+*/
+
+/*
+  function ReEstFreq: sinusoid reestimation by demodulating frequency.
+
+  In: x[Wid+Offst*(FrCount-1)]: waveform data
+      FrCount, Wid, Offst: frame count, frame size and hop size
+      fbuf[FrCount], ns[FrCount]: initial frequency estiamtes and their timing
+      win[Wid]: window function for estimating demodulated sinusoid
+      M, c[], iH2: cosine-family window specification parameters, must be consistent with win[]
+      Wids[FrCount]: specifies frame sizes for estimating individual frames of demodulated sinusoid, optional
+      w[Wid/2], ps[Wid], xs[Wid], xc[Wid], fa[FrCount-1], fb[FrCount-1], fc[FrCount-1], fd[FrCount-1]: buffers
+  Out: fbuf[FrCount], abuf[FrCount], pbuf[FrCount]: reestimated frequencies, amplitudes and phase angles
+
+  No return value.
+*/
+void ReEstFreq(int FrCount, int Wid, int Offst, double* x, double* fbuf, double* abuf, double* pbuf, double* win, int M, double* c, double iH2, cdouble* w, cdouble* xc, cdouble* xs, double* ps, double* fa, double* fb, double* fc, double* fd, double* ns, int* Wids)
+{
+  int hWid=Wid/2;
+  //reestimate using frequency track
+  CubicSpline(FrCount-1, fa, fb, fc, fd, ns, fbuf, 0, 1);
+  for (int fr=0; fr<FrCount; fr++)
+  {
+    //find ps
+    if (fr==0)
+    {
+      double lfd=0, lfc=fc[0], lfb=fb[0], lfa=fa[0];
+      for (int j=0; j<Wid; j++)
+      {
+         double lx=j-hWid;
+         ps[j]=2*M_PI*lx*(lfd+lx*(lfc/2+lx*(lfb/3+lx*lfa/4)));
+      }
+//      memset(ps, 0, sizeof(double)*hWid);
+    }
+    else if (fr==FrCount-1)
+    {
+      int lfr=FrCount-2;
+      double lfc=fc[lfr], lfb=fb[lfr], lfa=fa[lfr];
+      double lfd=-(hWid*(lfc+hWid*(lfb+hWid*lfa)));
+      ps[0]=-2*M_PI*hWid*(lfd+hWid*(lfc/2+hWid*(lfb/3+hWid*lfa/4)));
+      for (int j=1; j<Wid; j++)
+      {
+        ps[j]=ps[0]+2*M_PI*j*(lfd+j*(lfc/2+j*(lfb/3+j*lfa/4)));
+      }
+//        memset(&ps[hWid], 0, sizeof(double)*hWid);
+    }
+    else
+    {
+      int lfr=fr-1;
+      double lfd=fd[lfr]-fd[fr], lfc=fc[lfr], lfb=fb[lfr], lfa=fa[lfr];
+      ps[0]=-2*M_PI*hWid*(lfd+hWid*(lfc/2+hWid*(lfb/3+hWid*lfa/4)));
+      for (int j=1; j<hWid+1; j++)
+      {
+        ps[j]=ps[0]+2*M_PI*j*(lfd+j*(lfc/2+j*(lfb/3+j*lfa/4)));
+      }
+      lfr=fr;
+      lfd=0, lfc=fc[lfr], lfb=fb[lfr], lfa=fa[lfr];
+      for (int j=1; j<hWid; j++)
+      {
+        ps[j+hWid]=2*M_PI*j*(lfd+j*(lfc/2+j*(lfb/3+j*lfa/4)));
+      }
+    }
+    double* ldata=&x[fr*Offst];
+    for (int j=0; j<Wid; j++)
+    {
+      xs[j].x=ldata[j]*cos(-ps[j]);
+      xs[j].y=ldata[j]*sin(-ps[j]);
+    }
+
+    if (Wids)
+    {
+      int lWid=Wids[fr], lhWid=Wids[fr]/2, lM;
+      SetTwiddleFactors(lWid, w);
+      double *lwin=NewWindow(wtHann, lWid), lc[4], liH2;
+      windowspec(wtHann, lWid, &lM, lc, &liH2);
+      CFFTCW(&xs[hWid-lhWid], lwin, NULL, NULL, log2(lWid), w, xc);
+      delete[] lwin;
+      double lf=fbuf[fr]*lWid, la, lp;
+      LSESinusoid(lf, lf-3, lf+3, xc, lWid, 3, lM, lc, liH2, la, lp, 1e-3);
+      if (la*2>abuf[fr]) fbuf[fr]=lf/lWid, abuf[fr]=la*2, pbuf[fr]=lp;
+    }
+    else
+    {
+      CFFTCW(xs, win, NULL, NULL, log2(Wid), w, xc);
+      double lf=fbuf[fr]*Wid, la, lp;
+      LSESinusoid(lf, lf-3, lf+3, xc, Wid, 3, M, c, iH2, la, lp, 1e-3);
+      if (la*2>abuf[fr])
+        fbuf[fr]=lf/Wid, abuf[fr]=la*2, pbuf[fr]=lp;
+    }
+  }
+}//ReEstFreq
+
+/*
+  function ReEstFreq_2: sinusoid reestimation by demodulating frequency. This is that same as ReEstFreq(...)
+  except that it calls Sinusoid(...) to synthesize the phase track used for demodulation and that it
+  does not allow variable window sizes for estimating demodulated sinusoid.
+
+  In: x[Wid+Offst*(FrCount-1)]: waveform data
+      FrCount, Wid, Offst: frame count, frame size and hop size
+      fbuf[FrCount], ns[FrCount]: initial frequency estiamtes and their timing
+      win[Wid]: window function for LSE sinusoid estimation
+      M, c[], iH2: cosine-family window specification parameters, must be consistent with M, c, iH2
+      w[Wid/2], xs[Wid], xc[Wid], f3[FrCount-1], f2[FrCount-1], f1[FrCount-1], f0[FrCount-1]: buffers
+  Out: fbuf[FrCount], abuf[FrCount], pbuf[FrCount]: reestimated frequencies, amplitudes and phase angles
+
+  No return value.
+*/
+void ReEstFreq_2(int FrCount, int Wid, int Offst, double* x, double* fbuf, double* abuf, double* pbuf, double* win, int M, double* c, double iH2, cdouble* w, cdouble* xc, cdouble* xs, double* f3, double* f2, double* f1, double* f0, double* ns)
+{
+  int hWid=Wid/2;
+  //reestimate using frequency track
+  CubicSpline(FrCount-1, f3, f2, f1, f0, ns, fbuf, 1, 1);
+  double *refcos=(double*)malloc8(sizeof(double)*Wid), *refsin=&refcos[hWid], ph=0, centralph;
+
+  memset(f0, 0, sizeof(double)*FrCount);
+
+    int N=Wid+Offst*(FrCount-1);
+    double* cosine=new double[N], *sine=new double[N];
+    Sinusoid(&cosine[hWid], &sine[hWid], -hWid, 0, f3[0], f2[0], f1[0], f0[0], ph);
+    for (int fr=0; fr<FrCount-1; fr++)
+    {
+      int ncentre=hWid+Offst*fr;
+      if (fr==FrCount-2) Sinusoid(&cosine[ncentre], &sine[ncentre], 0, Wid, f3[fr], f2[fr], f1[fr], f0[fr], ph);
+      else Sinusoid(&cosine[ncentre], &sine[ncentre], 0, hWid, f3[fr], f2[fr], f1[fr], f0[fr], ph);
+    }
+    double err=0;
+    for (int n=0; n<N; n++) {double tmp=cosine[n]-x[n-hWid]; err+=tmp*tmp; tmp=cosine[n]*cosine[n]+sine[n]*sine[n]-1; err+=tmp*tmp;}
+
+  ph=0;
+  for (int fr=0; fr<FrCount; fr++)
+  {
+    double* ldata=&x[fr*Offst-hWid];
+
+    //store first half of demodulated frame to xs[0:hWid-1]
+    if (fr==0)
+    {
+      Sinusoid(&refcos[hWid], &refsin[hWid], -hWid, 0, f3[0], f2[0], f1[0], f0[0], ph);
+      for (int i=0; i<hWid; i++) xs[i].x=ldata[i]*refcos[i], xs[i].y=-ldata[i]*refsin[i];
+    }
+    else
+    {
+      ph=0;
+      Sinusoid(refcos, refsin, 0, hWid, f3[fr-1], f2[fr-1], f1[fr-1], f0[fr-1], ph);
+      for (int i=0; i<hWid; i++) xs[i].x=ldata[i]*refcos[i], xs[i].y=-ldata[i]*refsin[i];
+    }
+
+    //taking care of phase angles
+    if (fr==FrCount-1) {double tmp=ph; ph=centralph; centralph=tmp;}
+    else centralph=ph;
+
+    double *lrefcos=&refcos[-hWid], *lrefsin=&refsin[-hWid];
+    //store second half of demodulated frame to xs[hWid:Wid-1]
+    if (fr==FrCount-1)
+    {
+      Sinusoid(lrefcos, lrefsin, hWid, Wid, f3[FrCount-2], f2[FrCount-2], f1[FrCount-2], f0[FrCount-2], ph);
+      for (int i=hWid; i<Wid; i++) xs[i].x=ldata[i]*lrefcos[i], xs[i].y=-ldata[i]*lrefsin[i];
+    }
+    else
+    {
+      Sinusoid(refcos, refsin, 0, hWid, f3[fr], f2[fr], f1[fr], f0[fr], ph);
+      for (int i=hWid; i<Wid; i++) xs[i].x=ldata[i]*lrefcos[i], xs[i].y=-ldata[i]*lrefsin[i];
+    }
+
+    CFFTCW(xs, win, NULL, NULL, log2(Wid), w, xc);
+    double lf=fbuf[fr]*Wid, la, lp;
+    LSESinusoid(lf, lf-3, lf+3, xc, Wid, 3, M, c, iH2, la, lp, 1e-3);
+    if (la*2>abuf[fr])
+      fbuf[fr]=lf/Wid, abuf[fr]=la*2, pbuf[fr]=lp+centralph;
+  }
+}//ReEstFreq_2
+
+/*
+  function ReEstFreqAmp: sinusoid reestimation by demodulating frequency and amplitude.
+
+  In: x[Wid+Offst*(FrCount-1)]: waveform data
+      FrCount, Wid, Offst: frame count, frame size and hop size
+      fbuf[FrCount], abuf[FrCount], ns[FrCount]: initial frequency and amplitude estiamtes and their
+        timing
+      win[Wid]: window function for estimating demodulated sinusoid
+      M, c[], iH2: cosine-family window specification parameters, must be consistent with win[]
+      Wids[FrCount]: specifies frame sizes for estimating individual frames of demodulated sinusoid,
+        optional
+      w[Wid/2], ps[Wid], xs[Wid], xc[Wid]: buffers
+      fa[FrCount-1], fb[FrCount-1], fc[FrCount-1], fd[FrCount-1]: buffers
+      aa[FrCount-1], ab[FrCount-1], ac[FrCount-1], ad[FrCount-1]: buffers
+  Out: fbuf[FrCount], abuf[FrCount], pbuf[FrCount]: reestimated frequencies, amplitudes and phase angles
+
+  No return value.
+*/
+void ReEstFreqAmp(int FrCount, int Wid, int Offst, double* x, double* fbuf, double* abuf, double* pbuf, double* win, int M, double* c, double iH2, cdouble* w, cdouble* xc, cdouble* xs, double* ps, double* as, double* fa, double* fb, double* fc, double* fd, double* aa, double* ab, double* ac, double* ad, double* ns, int* Wids)
+{
+  int hWid=Wid/2;
+  //reestimate using amplitude and frequency track
+  CubicSpline(FrCount-1, fa, fb, fc, fd, ns, fbuf, 0, 1);
+  CubicSpline(FrCount-1, aa, ab, ac, ad, ns, abuf, 0, 1);
+  for (int fr=0; fr<FrCount; fr++)
+  {
+    if (fr==0)
+    {
+      double lfd=0, lfc=fc[0], lfb=fb[0], lfa=fa[0],
+             lad=ad[0], lac=ac[0], lab=ab[0], laa=aa[0];
+      for (int j=0; j<Wid; j++)
+      {
+        double lx=j-hWid;
+        ps[j]=2*M_PI*lx*(lfd+lx*(lfc/2+lx*(lfb/3+lx*lfa/4)));
+      }
+      for (int j=0; j<Wid; j++)
+      {
+        double lx=j-hWid;
+        as[j]=lad+lx*(lac+lx*(lab+lx*laa));
+      }
+    }
+    else if (fr==FrCount-1)
+    {
+      int lfr=FrCount-2;
+      double lfc=fc[lfr], lfb=fb[lfr], lfa=fa[lfr];
+      double lfd=-(hWid*(lfc+hWid*(lfb+hWid*lfa)));
+      double lad=ad[lfr], lac=ac[lfr], lab=ab[lfr], laa=aa[lfr];
+      ps[0]=-2*M_PI*hWid*(lfd+hWid*(lfc/2+hWid*(lfb/3+hWid*lfa/4)));
+      for (int j=1; j<Wid; j++)
+      {
+        ps[j]=ps[0]+2*M_PI*j*(lfd+j*(lfc/2+j*(lfb/3+j*lfa/4)));
+      }
+      as[0]=ad[lfr];
+      for (int j=0; j<Wid; j++)
+      {
+        as[j]=lad+j*(lac+j*(lab+j*laa));
+      }
+    }
+    else
+    {
+      int lfr=fr-1;
+      double lfd=fd[lfr]-fd[fr], lfc=fc[lfr], lfb=fb[lfr], lfa=fa[lfr];
+      double lad=ad[lfr], lac=ac[lfr], lab=ab[lfr], laa=aa[lfr];
+      ps[0]=-2*M_PI*hWid*(lfd+hWid*(lfc/2+hWid*(lfb/3+hWid*lfa/4)));
+      for (int j=0; j<hWid+1; j++)
+      {
+        ps[j]=ps[0]+2*M_PI*j*(lfd+j*(lfc/2+j*(lfb/3+j*lfa/4)));
+        as[j]=lad+j*(lac+j*(lab+j*laa));
+      }
+      lfr=fr;
+      lfd=0, lfc=fc[lfr], lfb=fb[lfr], lfa=fa[lfr];
+      lad=ad[lfr], lac=ac[lfr], lab=ab[lfr], laa=aa[lfr];
+      for (int j=1; j<hWid; j++)
+      {
+        ps[j+hWid]=2*M_PI*j*(lfd+j*(lfc/2+j*(lfb/3+j*lfa/4)));
+        as[j+hWid]=lad+j*(lac+j*(lab+j*laa));
+      }
+    }
+    double *ldata=&x[fr*Offst];
+    for (int j=0; j<Wid; j++)
+    {
+      double tmp;
+      if ((fr==0 && j<hWid) || (fr==FrCount-1 && j>=hWid)) tmp=1;
+      else if (as[hWid]>100*as[j]) tmp=100;
+      else tmp=as[hWid]/as[j];
+      tmp=tmp*ldata[j];
+      xs[j].x=tmp*cos(-ps[j]);
+      xs[j].y=tmp*sin(-ps[j]);
+    }
+
+    if (Wids)
+    {
+      int lWid=Wids[fr], lhWid=Wids[fr]/2, lM;
+      SetTwiddleFactors(lWid, w);
+      double *lwin=NewWindow(wtHann, lWid), lc[4], liH2;
+      windowspec(wtHann, lWid, &lM, lc, &liH2);
+      CFFTCW(&xs[hWid-lhWid], lwin, NULL, NULL, log2(lWid), w, xc);
+      delete[] lwin;
+      double lf=fbuf[fr]*lWid, la, lp;
+      LSESinusoid(lf, lf-3, lf+3, xc, lWid, 3, lM, lc, liH2, la, lp, 1e-3);
+      if (la*2>abuf[fr]) fbuf[fr]=lf/lWid, abuf[fr]=la*2, pbuf[fr]=lp;
+    }
+    else
+    {
+      CFFTCW(xs, win, NULL, NULL, log2(Wid), w, xc);
+      double lf=fbuf[fr]*Wid, la, lp;
+      LSESinusoid(lf, lf-3, lf+3, xc, Wid, 3, M, c, iH2, la, lp, 1e-3);
+      if (la*2>abuf[fr]) fbuf[fr]=lf/Wid, abuf[fr]=la*2, pbuf[fr]=lp;
+    }
+  }
+}//ReEstFreqAmp
+
+/*
+  function Reestimate2: iterative demodulation method for sinusoid parameter reestimation.
+
+  In: x[(FrCount-1)*Offst+Wid]: waveform data
+      FrCount, Wid, Offst: frame count, frame size and hop size
+      win[Wid]: window function
+      M, c[], iH2: cosine-family window specification parameters, must be consistent with win[]
+      Wids[FrCount]: specifies frame sizes for estimating individual frames of demodulated sinusoid,
+        optional
+      maxiter: maximal number of iterates
+      ae[FrCount], fe[FrCount], pe[FrCount]: initial amplitude, frequency and phase estimates
+  Out: aret[FrCount], fret[FrCount], pret[FrCount]: reestimated amplitudes, frequencies and phase angles
+
+  Returns the number of unused iterates left of the total of maxiter.
+*/
+int Reestimate2(int FrCount, int Wid, int Offst, double* win, int M, double* c, double iH2, double* x, double* ae, double* fe, double* pe, double* aret, double* fret, double *pret, int maxiter, int* Wids)
+{
+  AllocateFFTBuffer(Wid, fft, w, xc);
+  double convep=1e-4, dif=0, lastdif=0; //convep is the hard-coded threshold that stops the iteration
+  int iter=1, hWid=Wid/2;
+
+  double *ns=new double[FrCount*12], *as=new double[Wid*5];
+  double *fbuf=&ns[FrCount], *abuf=&ns[FrCount*2],
+         *aa=&ns[FrCount*3], *ab=&ns[FrCount*4], *ac=&ns[FrCount*5], *ad=&ns[FrCount*6],
+         *fa=&ns[FrCount*7], *fb=&ns[FrCount*8], *fc=&ns[FrCount*9], *fd=&ns[FrCount*10],
+         *pbuf=&ns[FrCount*11];
+  double *ps=&as[Wid];
+  cdouble *xs=(cdouble*)&as[Wid*3];
+
+  memcpy(fbuf, fe, sizeof(double)*FrCount);
+  memcpy(abuf, ae, sizeof(double)*FrCount);
+  memcpy(pbuf, pe, sizeof(double)*FrCount);
+  for (int i=0; i<FrCount; i++)
+  {
+    ns[i]=hWid+i*Offst;
+  }
+
+  while (iter<=maxiter)
+  {
+    ReEstFreq(FrCount, Wid, Offst, x, fbuf, abuf, pbuf, win, M, c, iH2, w, xc, xs, ps, fa, fb, fc, fd, ns, Wids);
+    ReEstFreq(FrCount, Wid, Offst, x, fbuf, abuf, pbuf, win, M, c, iH2, w, xc, xs, ps, fa, fb, fc, fd, ns, Wids);
+    ReEstFreqAmp(FrCount, Wid, Offst, x, fbuf, abuf, pbuf, win, M, c, iH2, w, xc, xs, ps, as, fa, fb, fc, fd, aa, ab, ac, ad, ns, Wids);
+
+    if (iter>1) lastdif=dif;
+    dif=0;
+    if (iter==1)
+    {
+      for (int fr=0; fr<FrCount; fr++)
+      {
+        if (fabs(abuf[fr])>fabs(ae[fr]))
+          dif+=fabs(fe[fr]-fbuf[fr])*Wid+fabs((ae[fr]-abuf[fr])/abuf[fr]);
+        else
+          dif+=fabs(fe[fr]-fbuf[fr])*Wid+fabs((ae[fr]-abuf[fr])/ae[fr]);
+      }
+    }
+    else
+    {
+      for (int fr=0; fr<FrCount; fr++)
+      {
+        if (fabs(abuf[fr])>fabs(aret[fr]))
+          dif+=fabs(fret[fr]-fbuf[fr])*Wid+fabs((aret[fr]-abuf[fr])/abuf[fr]);
+        else
+          dif+=fabs(fret[fr]-fbuf[fr])*Wid+fabs((aret[fr]-abuf[fr])/aret[fr]);
+      }
+    }
+    memcpy(fret, fbuf, sizeof(double)*FrCount);
+    memcpy(aret, abuf, sizeof(double)*FrCount);
+    dif/=FrCount;
+    if (fabs(dif)<convep || (iter>1 && fabs(dif-lastdif)<convep*lastdif)) break;
+    iter++;
+  }
+
+  memcpy(pret, pbuf, sizeof(double)*FrCount);
+
+  delete[] ns;
+  delete[] as;
+  delete[] fft;
+
+  return maxiter-iter;
+}//Reestimate2
+
+//---------------------------------------------------------------------------
+/*
+    Derivative method as proposed in DAFx09
+
+    Further reading: Wen X. and M. Sandler, "Notes on model-based non-stationary sinusoid estimation methods
+    using derivatives," in Proc. DAFx'09, Como, 2009.
+*/
+
+/*
+  function Derivative: derivative method for estimating amplitude derivative, frequency, and frequency derivative given
+  signal and its derivatives.
+
+  In: x[Wid], dx[Wid], ddx[Wid]: waveform and its derivatives
+      win[Wid]: window function
+      f0: initial digital frequency estimate
+  Out: f0: new estimate of digital frequency
+       f1, a1: estimates of frequency and amplitude derivatives
+
+  No return value.
+*/
+void Derivative(int Wid, double* win, cdouble* x, cdouble* dx, cdouble* ddx, double& f0, double* f1, double* a0, double* a1, double* ph)
+{
+  AllocateFFTBuffer(Wid, fft, W, X);
+  CFFTCW(x, win, fft, NULL, log2(Wid), W, X);
+  int m=f0*Wid, m0=m-10, m1=m+10, hWid=Wid/2;
+  if (m0<0) m0=0; if (m1>hWid) m1=hWid;
+  for (int n=m0; n<=m1; n++) if (fft[n]>fft[m]) m=n;
+  cdouble Sw=0, S1w=0, S2w=0;
+  for (int n=0; n<Wid; n++)
+  {
+    cdouble tmp=x[n]*win[n];
+    Sw+=tmp.rotate(-2*M_PI*m*(n-hWid)/Wid);
+    tmp=dx[n]*win[n];
+    S1w+=tmp.rotate(-2*M_PI*m*(n-hWid)/Wid);
+  }
+  double omg0=(S1w/Sw).y;
+  Sw=0, S1w=0;
+  for (int n=0; n<Wid; n++)
+  {
+    cdouble tmp=x[n]*win[n];
+    Sw+=tmp.rotate(-omg0*(n-hWid)/Wid);
+    tmp=dx[n]*win[n];
+    S1w+=tmp.rotate(-omg0*(n-hWid)/Wid);
+    tmp=ddx[n]*win[n];
+    S2w+=tmp.rotate(-omg0*(n-hWid)/Wid);
+  }
+  omg0=(S1w/Sw).y;
+  double miu0=(S1w/Sw).x;
+  double psi0=(S2w/Sw).y-2*miu0*omg0;
+
+  f0=omg0/(2*M_PI);
+  *f1=psi0/(2*M_PI);
+  *a1=miu0;
+
+  FreeFFTBuffer(fft);
+}//Derivative
+
+/*
+  function Xkw: computes windowed spectrum of x and its derivatives up to order K at angular frequency omg,
+  from x using window w and its derivatives.
+
+  In: x[Wid]: waveform data
+      w[K+1][Wid]: window functions and its derivatives up to order K
+      omg: angular frequency
+  Out: X[K+1]: windowed spectrum and its derivatives up to order K
+
+  No return value. This function is for internal use.
+*/
+void Xkw(cdouble* X, int K, int Wid, double* x, double** w, double omg)
+{
+  int hWid=Wid/2;
+  //calculate the first row
+  memset(X, 0, sizeof(cdouble)*(K+1));
+  for (int i=0; i<Wid; i++)
+  {
+    double n=i-hWid;
+    double ph=omg*n;
+    for (int k=0; k<=K; k++)
+    {
+      cdouble tmp=x[i]*w[k][i];
+      X[k]+=tmp.rotate(-ph);
+    }
+  }
+  //calculate the rest rows
+  for (int k=1; k<=K; k++)
+  {
+    cdouble *thisX=&X[k], *lastX=&X[k-1];
+			for (int kk=K-k; kk>=0; kk--) thisX[kk]=-lastX[kk+1]+cdouble(0, omg)*lastX[kk];
+  }
+}//Xkw
+
+/*
+  function Xkw: computes windowed spectrum of x and its derivatives up to order K at angular frequency
+  omg, from x and its derivatives using window w.
+
+  In: x[K+1][Wid]: waveform data and its derivatives up to order K.
+      w[Wid]: window function
+      omg: angular frequency
+  Out: X[K+1]: windowed spectrum and its derivatives up to order K
+
+  No return value. This function is for testing only.
+*/
+void Xkw(cdouble* X, int K, int Wid, double** x, double* w, double omg)
+{
+  int hWid=Wid/2;
+  memset(X, 0, sizeof(cdouble)*(K+1));
+  for (int i=0; i<Wid; i++)
+  {
+    double n=i-hWid;
+    double ph=omg*n;
+    for (int k=0; k<=K; k++)
+    {
+      cdouble tmp=x[k][i]*w[i];
+      X[k]+=tmp.rotate(-ph);
+    }
+  }
+}//Xkw
+
+/*
+  function Derivative: derivative method for estimating the model log(s)=h[M]'r[M], by discarding extra
+  equations
+
+  In: s[Wid]: waveform data
+      win[][Wid]: window function and its derivatives
+      h[M], dh[M]: pointers to basis functions and their derivatives
+      harg: pointer argument to be used by calls to functions in h[] amd dh[].
+      p0[p0s]: zero-constraints on real parts of r, i.e. Re(r[p0[*]]) are constrained to 0.
+      q0[q0s]: zero-constraints on imaginary parts of r, i.e. Im(r[q0[*]]) are constrained to 0.
+      omg: initial angular frequency
+  Out: r[M]: estimated coefficients to h[M].
+
+  No return value.
+*/
+void Derivative(int M, double (**h)(double t, void*), double (**dh)(double t, void*), cdouble* r, int p0s, int* p0, int q0s, int* q0, int Wid, double* s, double** win, double omg, void* harg)
+{
+	int hWid=Wid/2, M1=M-1;
+	int Kr=(M1)*2-p0s-q0s; //number of real unknowns apart from p0 and q0
+	int Kc=ceil(Kr/2.0); //number of derivatives required
+
+	//ind marks the 2*M1 real elements of an M1-array of complex unknowns with
+	//  numerical indices (0-based) or -1 if it is not a real unknown variable
+	//uind marks the Kr real unknowns with their positions in ind
+	int *uind=new int[Kr], *ind=new int[2*M1];
+	memset(ind, 0, sizeof(int)*2*M1);
+	for (int p=0; p<p0s; p++) ind[2*(p0[p]-1)]=-1;
+	for (int q=0; q<q0s; q++) ind[2*(q0[q]-1)+1]=-1;
+	{
+		int p=0, up=0;
+		while (p<2*M1)
+		{
+			if (ind[p]>=0)
+			{
+				uind[up]=p;
+				ind[p]=up;
+				up++;
+			}
+			p++;
+		}
+		if (up!=Kr) throw("");
+	}
+
+	cdouble* Skw=new cdouble[M];
+	Xkw(Skw, Kc, Wid, s, win, omg);
+
+	double* x=new double[Wid];
+	cdouble** Allocate2(cdouble, M, Kc, Smkw);
+	for (int m=1; m<M; m++)
+	{
+		for (int i=0; i<Wid; i++) x[i]=dh[m](i-hWid, harg)*s[i];
+		Xkw(Smkw[m], Kc-1, Wid, x, win, omg);
+	}
+
+	//allocate buffer for linear system A(pq)=b
+	Alloc2(2*Kc+2, Kr, A); double** AA; double *bb, *pqpq;
+	double *b=A[2*Kc], *pq=A[2*Kc+1];
+	for (int k=0; k<Kr; k++) b[k]=((double*)(&Skw[1]))[k];
+	//		*pq=(double*)(&r[1]);
+	for (int k=0; k<Kc; k++) //looping through rows of A
+	{
+    //columns of A includes rows of Smkw corresponding to real unknowns
+		for (int m=0; m<M1; m++)
+		{
+			int lind;
+			if ((lind=ind[2*m])>=0) //the real part being unknown
+			{
+				A[2*k][lind]=Smkw[m+1][k].x;
+				A[2*k+1][lind]=Smkw[m+1][k].y;
+			}
+			if ((lind=ind[2*m+1])>=0) //the imag part being unknown
+			{
+				A[2*k+1][lind]=Smkw[m+1][k].x;
+				A[2*k][lind]=-Smkw[m+1][k].y;
+			}
+		}
+	}
+  
+	bool dropeq=(2*Kc-1==Kr);
+	if (dropeq)
+	{
+		Allocate2(double, Kr+2, Kr, AA);
+		bb=AA[Kr], pqpq=AA[Kr+1];
+		memcpy(AA[0], A[0], sizeof(double)*Kr*(Kr-1));
+		memcpy(AA[Kr-1], A[Kr], sizeof(double)*Kr);
+		memcpy(bb, b, sizeof(double)*(Kr-1));
+		bb[Kr-1]=((double*)(&Skw[1]))[Kr];
+	}
+
+	double det;
+	GECP(Kr, pq, A, b, &det);
+	if (dropeq)
+	{
+		double det2;
+		GECP(Kr, pqpq, AA, bb, &det2);
+		if (fabs(det2)>fabs(det)) memcpy(pq, pqpq, sizeof(double)*Kr);
+		DeAlloc2(AA);
+	}
+	memset(&r[1], 0, sizeof(double)*M1*2);
+	for (int k=0; k<Kr; k++) ((double*)(&r[1]))[uind[k]]=pq[k];
+
+	//estiamte r0
+	cdouble e0=0;
+	for (int i=0; i<Wid; i++)
+	{
+		cdouble expo=0;
+		double n=i-hWid;
+		for (int m=1; m<M; m++){double lhm=h[m](n, harg); expo+=r[m]*lhm;}
+		cdouble tmp=exp(expo)*win[0][i];
+		e0+=tmp.rotate(-omg*n);
+	}
+	r[0]=log(Skw[0]/e0);
+
+	delete[] x;
+	delete[] Skw;
+	delete[] uind;
+	delete[] ind;
+	DeAlloc2(Smkw);
+	DeAlloc2(A);
+}//Derivative*/
+
+/*
+  function DerivativeLS: derivative method for estimating the model log(s)=h[M]'r[M], least-square
+  implementation
+
+  In: s[Wid]: waveform data
+      win[][Wid]: window function and its derivatives
+      h[M], dh[M]: pointers to basis functions and their derivatives
+      harg: pointer argument to be used by calls to functions in h[] amd dh[].
+      K: number of derivatives to take
+      p0[p0s]: zero-constraints on real parts of r, i.e. Re(r[p0[*]]) are constrained to 0.
+      q0[q0s]: zero-constraints on imaginary parts of r, i.e. Im(r[q0[*]]) are constrained to 0.
+      omg: initial angular frequency
+  Out: r[M]: estimated coefficients to h[M].
+
+  No return value.
+*/
+void DerivativeLS(int K, int M, double (**h)(double t, void* harg), double (**dh)(double t, void* harg), cdouble* r, int p0s, int* p0, int q0s, int* q0, int Wid, double* s, double** win, double omg, void* harg, bool r0)
+{
+	int hWid=Wid/2, M1=M-1;
+	int Kr=(M1)*2-p0s-q0s; //number of real unknowns apart from p0 and q0
+	int Kc=ceil(Kr/2.0); //number of derivatives required
+	if (Kc<K) Kc=K;
+
+	int *uind=new int[Kr], *ind=new int[2*M1];
+	memset(ind, 0, sizeof(int)*2*M1);
+	for (int p=0; p<p0s; p++) ind[2*(p0[p]-1)]=-1;
+	for (int q=0; q<q0s; q++) ind[2*(q0[q]-1)+1]=-1;
+	{int p=0, up=0; while (p<2*M1){if (ind[p]>=0){uind[up]=p;	ind[p]=up; up++;}	p++;} if (up!=Kr) throw("");}
+
+	//allocate buffer for linear system A(pq)=b
+	cdouble* Skw=new cdouble[Kc+1];
+	double* x=new double[Wid];
+	cdouble** Allocate2(cdouble, M, Kc, Smkw);
+
+	Alloc2(2*Kc+2, 2*Kc, A);
+	double *b=A[2*Kc], *pq=A[2*Kc+1];
+
+	  Xkw(Skw, Kc, Wid, s, win, omg);
+	  for (int m=1; m<M; m++)
+	  {
+		  for (int i=0; i<Wid; i++) x[i]=dh[m](i-hWid, harg)*s[i];
+		  Xkw(Smkw[m], Kc-1, Wid, x, win, omg);
+	  }
+
+	  for (int k=0; k<2*Kc; k++) b[k]=((double*)(&Skw[1]))[k];
+		for (int k=0; k<Kc; k++)
+		{
+		  for (int m=0; m<M1; m++)
+		  {
+			  int lind;
+				if ((lind=ind[2*m])>=0)
+			  {
+				  A[2*k][lind]=Smkw[m+1][k].x;
+				  A[2*k+1][lind]=Smkw[m+1][k].y;
+				}
+			  if ((lind=ind[2*m+1])>=0)
+			  {
+				  A[2*k+1][lind]=Smkw[m+1][k].x;
+				  A[2*k][lind]=-Smkw[m+1][k].y;
+			  }
+		  }
+	  }
+
+	if (2*Kc==Kr) GECP(Kr, pq, A, b);
+	else LSLinear2(2*Kc, Kr, pq, A, b);
+
+	memset(&r[1], 0, sizeof(double)*M1*2);
+	for (int k=0; k<Kr; k++) ((double*)(&r[1]))[uind[k]]=pq[k];
+	//estiamte r0
+  if (r0)
+  {
+		cdouble e0=0;
+  	for (int i=0; i<Wid; i++)
+	  {
+		  cdouble expo=0;
+			double n=i-hWid;
+  		for (int m=1; m<M; m++){double lhm=h[m](n, harg); expo+=r[m]*lhm;}
+	  	cdouble tmp=exp(expo)*win[0][i];
+			e0+=tmp.rotate(-omg*n);
+		}
+		r[0]=log(Skw[0]/e0);
+  }
+	delete[] x;
+	delete[] Skw;
+	delete[] uind;
+	delete[] ind;
+	DeAlloc2(Smkw);
+	DeAlloc2(A);
+}//DerivativeLS
+
+/*
+  function DerivativeLS: derivative method for estimating the model log(s)=h[M]'r[M] using Fr
+  measurement points a quarter of Wid apart from each other, implemented by least-square.
+
+  In: s[Wid+(Fr-1)*Wid/4]: waveform data
+      win[][Wid]: window function and its derivatives
+      h[M], dh[M]: pointers to basis functions and their derivatives
+      harg: pointer argument to be used by calls to functions in h[] amd dh[].
+      Fr: number of measurement points
+      K: number of derivatives to take at each measurement point
+      p0[p0s]: zero-constraints on real parts of r, i.e. Re(r[p0[*]]) are constrained to 0.
+      q0[q0s]: zero-constraints on imaginary parts of r, i.e. Im(r[q0[*]]) are constrained to 0.
+      omg: initial angular frequency
+      r0: specifies if r[0] is to be computed.
+  Out: r[M]: estimated coefficients to h[M].
+
+  No return value.
+*/
+void DerivativeLS(int Fr, int K, int M, double (**h)(double t, void* harg), double (**dh)(double t, void* harg), cdouble* r, int p0s, int* p0, int q0s, int* q0, int Wid, double* s, double** win, double omg, void* harg, bool r0)
+{
+	int hWid=Wid/2, qWid=Wid/4, M1=M-1;
+	int Kr=(M1)*2-p0s-q0s; //number of real unknowns apart from p0 and q0
+	int Kc=ceil(Kr/2.0/Fr); //number of derivatives required
+	if (Kc<K) Kc=K;
+
+	int *uind=new int[Kr], *ind=new int[2*M1];
+	memset(ind, 0, sizeof(int)*2*M1);
+	for (int p=0; p<p0s; p++) ind[2*(p0[p]-1)]=-1;
+	for (int q=0; q<q0s; q++) ind[2*(q0[q]-1)+1]=-1;
+	{int p=0, up=0;	while (p<2*M1){if (ind[p]>=0){uind[up]=p;	ind[p]=up; up++;}	p++;}}
+
+	//allocate buffer for linear system A(pq)=b
+	cdouble* Skw=new cdouble[Kc+1], Skw00;
+	double* x=new double[Wid];
+	cdouble** Allocate2(cdouble, M, Kc, Smkw);
+
+	Alloc2(2*Fr*Kc, 2*Fr*Kc, A);
+	double *pq=new double[2*Fr*Kc], *b=new double[2*Fr*Kc];
+
+	for (int fr=0; fr<Fr; fr++)
+	{
+		int Offst=qWid*fr; double* ss=&s[Offst];
+
+		Xkw(Skw, Kc, Wid, ss, win, omg); if (fr==0) Skw00=Skw[0];
+		for (int m=1; m<M; m++)
+		{
+			for (int i=0; i<Wid; i++) x[i]=dh[m](i+Offst-hWid, harg)*ss[i];
+			Xkw(Smkw[m], Kc-1, Wid, x, win, omg);
+		}
+
+		for (int k=0; k<2*Kc; k++) b[2*fr*Kc+k]=((double*)(&Skw[1]))[k];
+		for (int k=0; k<Kc; k++)
+		{
+			for (int m=0; m<M1; m++)
+			{
+				int lind;
+				if ((lind=ind[2*m])>=0)
+				{
+					A[2*fr*Kc+2*k][lind]=Smkw[m+1][k].x;
+					A[2*fr*Kc+2*k+1][lind]=Smkw[m+1][k].y;
+				}
+				if ((lind=ind[2*m+1])>=0)
+				{
+					A[2*fr*Kc+2*k+1][lind]=Smkw[m+1][k].x;
+					A[2*fr*Kc+2*k][lind]=-Smkw[m+1][k].y;
+				}
+			}
+		}
+	}
+	if (2*Fr*Kc==Kr) GECP(Kr, pq, A, b);
+	else LSLinear2(2*Fr*Kc, Kr, pq, A, b);
+
+	memset(&r[1], 0, sizeof(double)*M1*2);
+	for (int k=0; k<Kr; k++) ((double*)(&r[1]))[uind[k]]=pq[k];
+	//estiamte r0
+	if (r0)
+	{
+		cdouble e0=0;
+		for (int i=0; i<Wid; i++)
+		{
+			cdouble expo=0;
+			double n=i-hWid;
+			for (int m=1; m<M; m++){double lhm=h[m](n, harg); expo+=r[m]*lhm;}
+			cdouble tmp=exp(expo)*win[0][i];
+			e0+=tmp.rotate(-omg*n);
+		}
+		r[0]=log(Skw00/e0);
+  }
+	delete[] x;
+	delete[] Skw;
+	delete[] uind;
+	delete[] ind;
+	DeAlloc2(Smkw);
+	DeAlloc2(A);
+	delete[] pq; delete[] b;
+}//DerivativeLS
+
+//---------------------------------------------------------------------------
+/*
+    Abe-Smith sinusoid estimator 2005
+
+    Further reading: M. Abe and J. O. Smith III, ¡°AM/FM rate estimation for time-varying sinusoidal
+    modeling,¡± in Proc. ICASSP'05, Philadelphia, 2005.
+*/
+
+/*
+  function RDFTW: windowed DTFT at frequency k bins
+
+  In: data[Wid]: waveform data
+      w[Wid]: window function
+      k: frequency, in bins
+  Out: Xr, Xi: real and imaginary parts of the DTFT of xw at frequency k bins
+
+  No return value.
+*/
+void RDFTW(double& Xr, double& Xi, double k, int Wid, double* data, double* w)
+{
+	Xr=Xi=0;
+	int hWid=Wid/2;
+	double* lw=&w[Wid];
+	for (int i=0; i<=Wid; i++)
+	{
+		double tmp;
+		tmp=*data**lw;
+		data++, lw--;
+//*
+    double ph=-2*M_PI*(i-hWid)*k/Wid;
+    Xr+=tmp*cos(ph);
+    Xi+=tmp*sin(ph); //*/
+  }
+}//RDFTW
+
+/*
+  function TFAS05: the Abe-Smith method 2005
+
+  In: data[Wid]: waveform data
+      w[Wid]: window function
+      res: resolution of frequency for QIFFT
+  Out: f, a, ph: frequency, amplitude and phase angle estimates
+       aesp, fslope: estimates of log amplitude and frequency derivatives
+
+  No return value.
+*/
+void TFAS05(double& f, double& t, double& a, double& ph, double& aesp, double& fslope, int Wid, double* data, double* w, double res)
+{
+	double fi=floor(f*Wid+0.5); //frequency (int) in bins
+	double xr0, xi0, xr_1, xi_1, xr1, xi1;
+	RDFTW(xr0, xi0, fi, Wid, data, w);
+	RDFTW(xr_1, xi_1, fi-res, Wid, data, w);
+	RDFTW(xr1, xi1, fi+res, Wid, data, w);
+	double winnorm=0; for (int i=0; i<=Wid; i++) winnorm+=w[i];
+	double y0=log(sqrt(xr0*xr0+xi0*xi0)/winnorm),
+         y_1=log(sqrt(xr_1*xr_1+xi_1*xi_1)/winnorm),
+         y1=log(sqrt(xr1*xr1+xi1*xi1)/winnorm);
+  double df=0;
+//*
+  if (y0<y1)
+  {
+    double newfi=fi+res;
+    while (y0<y1)
+    {
+      y_1=y0, xr_1=xr0, xi_1=xi0;
+      y0=y1, xr0=xr1, xi0=xi1;
+      newfi+=res;
+      RDFTW(xr1, xi1, newfi, Wid, data, w);
+      y1=log(sqrt(xr1*xr1+xi1*xi1)/winnorm);
+      fi+=res;
+    }
+  }
+  else if(y0<y_1)
+  {
+    double newfi=fi-res;
+    while (y0<y_1)
+    {
+      y1=y0, xr1=xr0, xi1=xi0;
+      y0=y_1, xr0=xr_1, xi0=xi_1;
+      newfi-=res;
+      RDFTW(xr_1, xi_1, newfi, Wid, data, w);
+      y_1=log(sqrt(xr_1*xr_1+xi_1*xi_1)/winnorm);
+      fi-=res;
+    }
+  }    //*/
+
+	double a2=(y1+y_1)*0.5-y0, a1=(y1-y_1)*0.5, a0=y0;
+  df=-a1*0.5/a2;
+  f=fi+df*res; //in bins
+  double y=a0-0.25*a1*a1/a2;
+  a=exp(y);
+	double ph0=(xi0==0 && xr0==0)?0:atan2(xi0, xr0),
+				 ph_1=(xi_1==0 && xr_1==0)?0:atan2(xi_1, xr_1),
+				 ph1=(xi1==0 && xr1==0)?0:atan2(xi1, xr1);
+  if (fabs(ph_1-ph0)>M_PI)
+  {
+    if (ph_1-ph0>0) ph_1-=M_PI*2;
+    else ph_1+=M_PI*2;
+  }
+  if (fabs(ph1-ph0)>M_PI)
+  {
+    if (ph1-ph0>0) ph1-=M_PI*2;
+    else ph1+=M_PI*2;
+  } 
+  double b2=(ph1+ph_1)*0.5-ph0, b1=(ph1-ph_1)*0.5, b0=ph0;
+  ph=b0+b1*(df+b2*df);
+  //now we have the QI estimates
+  double uff=2*a2, vf=b1+2*b2*df, vff=2*b2;
+	double dfdp=Wid/(2*M_PI*res);
+	double upp=uff*dfdp*dfdp, vp=vf*dfdp, vpp=vff*dfdp*dfdp;
+	double p=-upp*0.5/(upp*upp+vpp*vpp);
+	double alf=-2*p*vp, beta=p*vpp/upp;
+	//*direct method
+	double beta_p=beta/p;
+	double feses=f-alf*beta/p /(2*M_PI)*Wid,
+				 yeses=y-alf*alf*0.25/p+0.25*log(1+beta_p*beta_p),
+				 pheses=ph+alf*alf*beta*0.25/p-0.5*atan(beta_p); //*/
+	/*adapted method
+	double zt[]={0, 0.995354, 0.169257, 1.393056, 0.442406, -0.717980, -0.251620, 0.177511, 0.158120, -0.503299};
+	double delt=res/Wid; double delt0=df*delt;
+	beta=zt[3]*beta+zt[4]*delt0*alf;
+	alf=(zt[1]+zt[2]*delt*delt)*alf;
+	double beta_p=beta/p;
+	double feses=f+zt[5]*alf*beta/p /(2*M_PI)*Wid,
+				 yeses=y+zt[6]*alf*alf/p+zt[7]*log(1+beta_p*beta_p),
+				 pheses=ph+zt[8]*alf*alf*beta/p+zt[9]*atan(beta_p); //*/
+	f=feses/Wid, a=exp(yeses), ph=pheses, fslope=2*beta/2/M_PI, aesp=alf;
+}//TFAS05
+
+/*
+  function TFAS05_enh: the Abe-Smith method 2005 enhanced by LSE amplitude and phase estimation
+
+  In: data[Wid]: waveform data
+      w[Wid]: window function
+      res: resolution of frequency for QIFFT
+  Out: f, a, ph: frequency, amplitude and phase angle estimates
+       aesp, fslope: estimates of log amplitude and frequency derivatives
+
+  No return value.
+*/
+void TFAS05_enh(double& f, double& t, double& a, double& ph, double& aesp, double& fslope, int Wid, double* data, double* w, double res)
+{
+	TFAS05(f, t, a, ph, aesp, fslope, Wid, data, w, res);
+	double xr=0, xi=0, p, win2=0;
+	for (int n=0; n<=Wid; n++)
+	{
+		double ni=n-Wid/2, tmp=data[n]*w[n]*w[n];//*exp(-aesp*(n-Wid/2));  if (IsInfinite(tmp)) continue;
+		p=-2*M_PI*(f+0.5*fslope*ni)*ni;
+		xr+=tmp*cos(p);
+		xi+=tmp*sin(p);
+		win2+=w[n]*w[n];
+	}
+	a=sqrt(xr*xr+xi*xi)/win2;
+	ph=(xr==0 && xi==0)?0:atan2(xi, xr);
+}//TFAS05_enh
+//version without returning aesp and fslope
+void TFAS05_enh(double& f, double& t, double& a, double& ph, int Wid, double* data, double* w, double res)
+{
+	double aesp, fslope;
+	TFAS05_enh(f, t, a, ph, aesp, fslope, Wid, data, w, res);
+}//TFAS05_enh
+
+//---------------------------------------------------------------------------
+/*
+  function DerivativeLSv_AmpPh: estimate the constant-term in the local derivative method. This is used
+  by the local derivative algorithm, whose implementation is found in the header file as templates.
+
+  In: sv0: inner product <s, v0>, where s is the sinusoid being estimated.
+      integr_h[M][Wid]: M vectors containing samples of the integral of basis functions h[M].
+      v0[M]: a test function
+      lmd[M]: coefficients to h[M]
+
+  Returns coefficient of integr_h[0]=1.
+*/
+cdouble DerivativeLSv_AmpPh(int Wid, int M, double** integr_h, cdouble* lmd, cdouble* v0, cdouble sv0)
+{
+  cdouble e0=0;
+  for (int n=0; n<Wid; n++)
+  {
+    cdouble expo=0;
+    for (int m=1; m<=M; m++) expo+=lmd[m]*integr_h[m][n];
+    e0+=exp(expo)**v0[n];
+  }
+  return log(sv0/e0);
+}//DerivativeLSv_AmpPh
+
+//---------------------------------------------------------------------------
+/*
+    Piecewise derivative algorithm
+
+    Further reading: Wen X. and M. Sandler, "Spline exponential approximation of time-varying
+    sinusoids," under review.
+*/
+
+/*
+  function setv: computes I test functions v[I] by modulation u[I] to frequency f
+
+  In: u[I+1][Wid], du[I+1][Wid]: base-band test functions and their derivatives
+      f: carrier frequency
+  Out: v[I][Wid], dv[I][Wid]: test functions and their derivatives
+
+  No return value.
+*/
+void setv(int I, int Wid, cdouble** v, cdouble** dv, double f, cdouble** u, cdouble** du)
+{
+  double fbin=floor(f*Wid+0.5)/Wid;
+  double omg=fbin*2*M_PI;
+  cdouble jomg=cdouble(0, omg);
+  for (int c=0; c<Wid; c++)
+  {
+    double t=c;
+    cdouble rot=polar(1.0, omg*t);
+    for (int i=0; i<I-1; i++) v[i][c]=u[i][c]*rot;
+    for (int i=0; i<I-1; i++) dv[i][c]=du[i][c]*rot+jomg*v[i][c];
+    //Here it is assumed that elements of u[] are modulated at 0, 1, -1, 2, -2, 3, -3, 4, ...;
+    //if f is under fbin then the closest ones are in order 0, -1, 1, -2, 3, -3, 3, .... This
+    //makes a difference to the whole of v[] only if I is even.
+    if (f>=fbin || I%2==1){v[I-1][c]=u[I-1][c]*rot; dv[I-1][c]=du[I-1][c]*rot+jomg*v[I-1][c];}
+    else{v[I-1][c]=u[I][c]*rot; dv[I-1][c]=du[I][c]*rot+jomg*v[I-1][c];}
+  }
+}//setv
+
+/*
+  function setvhalf: computes I half-size test functions v[I] by modulation u[I] to frequency f.
+
+  In: u[I][hWid*2], du[I][Wid*2]: base-band test functions and their derivatives
+      f: carrier frequency
+  Out: v[I][hWid], dv[hWid]: half-size test functions and their derivatives
+
+  No return value.
+*/void setvhalf(int I, int hWid, cdouble** v, cdouble** dv, double f, cdouble** u, cdouble** du)
+{
+  double fbin=floor(f*hWid)/hWid;
+  double omg=fbin*2*M_PI;
+  cdouble jomg=cdouble(0, omg);
+  for (int c=0; c<hWid; c++)
+  {
+    double t=c;
+    cdouble rot=polar(1.0, omg*t);
+    for (int i=0; i<I; i++) v[i][c]=u[i][c*2]*rot;
+    for (int i=0; i<I; i++) dv[i][c]=rot*du[i][c*2]*cdouble(2.0)+jomg*v[i][c];
+  }
+}//setvhalf
+
+//#define ERROR_CHECK
+
+/*
+  function DerivativePiecewise: Piecewise derivative algorithm. In this implementation of the piecewise
+  method the test functions v are constructed from I "basic" (single-frame) test functions, each
+  covering the same period of 2T, by shifting these I functions by steps of T. A total number of (L-1)I
+  test functions are used.
+
+  In: s[LT+1]: waveform data
+      ds[LT+1]: derivative of s[LT], used only if ERROR_CHECK is defined.
+      L, T: number and length of pieces.
+      N: number of independent coefficients
+      h[M][T]: piecewise basis functions
+      A[L][M][N]: L matrices that map independent coefficients onto component coefficients over the L pieces
+      u[I][2T}, du[I][2T]: base-band test functions
+      f[L+1]: reference frequencies at 0, T, ..., LT, only f[1]...f[L-1] are used
+      endmode: set to 1 or 3 to apply half-size testing over [0, T], to 2 or 3 to apply over [LT-T, LT]
+  Out: aita[N]: independent coefficients
+
+  No return value.
+*/
+void DerivativePiecewise(int N, cdouble* aita, int L, double* f, int T, cdouble* s, double*** A, int M, double** h, int I, cdouble** u, cdouble** du, int endmode, cdouble* ds)
+{
+  MList* mlist=new MList;
+  int L_1=(endmode==0)?(L-1):((endmode==3)?(L+1):L);
+  cdouble** Allocate2L(cdouble, L_1, I, sv, mlist);
+  cdouble** Allocate2(cdouble, I, T*2, v);
+  cdouble** Allocate2(cdouble, I, T*2, dv);
+  //compute <sr, v>
+  cdouble*** Allocate3L(cdouble, L_1, I, N, srv, mlist);
+  cdouble** Allocate2L(cdouble, I, M, shv1, mlist);
+  cdouble** Allocate2L(cdouble, I, M, shv2, mlist);
+
+#ifdef ERROR_CHECK
+  cdouble dsv1[128], dsv2[128];
+#endif
+  for (int l=0; l<L-1; l++)
+  {
+    //v from u given f[l]
+    double fbin=floor(f[l+1]*T*2)/(T*2.0);
+    double omg=fbin*2*M_PI;
+    cdouble jomg=cdouble(0, omg);
+    for (int c=0; c<T*2; c++)
+    {
+      double t=c-T;
+      cdouble rot=polar(1.0, omg*t);
+      for (int i=0; i<I; i++) v[i][c]=u[i][c]*rot;
+      for (int i=0; i<I; i++) dv[i][c]=du[i][c]*rot+jomg*v[i][c];
+    }
+
+    //compute -<s, v'> over the lth frame
+    cdouble* ls=&s[l*T]; for (int i=0; i<I; i++) sv[l][i]=-Inner(2*T, ls, dv[i]);
+
+    //compute <sr, v> over the lth frame
+    cdouble *ls1=&s[l*T], *ls2=&s[l*T+T];
+    for (int i=0; i<I; i++)
+      for (int m=0; m<M; m++)
+        shv1[i][m]=Inner(T, ls1, h[m], v[i]), shv2[i][m]=Inner(T, ls2, h[m], &v[i][T]);
+    //memset(srv[l][0], 0, sizeof(cdouble)*I*N);
+    MultiplyXY(I, M, N, srv[l], shv1, A[l]);
+    MultiAddXY(I, M, N, srv[l], shv2, A[l+1]);
+
+#ifdef ERROR_CHECK
+    //error check: <s', v>=-<s, v'>
+    if (ds)
+    {
+      cdouble* lds=&ds[l*T];
+      for (int i=0; i<I && l*I+1<36; i++)
+      {
+        cdouble lsv=Inner(2*T, lds, v[i]); //compute <s', v[i]>
+        //cdouble* ls=&s[l*T];
+        //cdouble lsv2=Inner(2*T, ls, dv[i]);
+        dsv1[l*I+i]=lsv-sv[l][i]; //i.e. <s', v[i]>=-<s, v[i]'>+dsv1[lI+i]
+      }
+
+      //error check: srv[l]*pq=<s',v>
+      for (int i=0; i<I && l*I+i<36; i++)
+      {
+        cdouble lsv=0;
+        for (int n=0; n<N; n++) lsv+=srv[l][i][n]*aita[n];
+        dsv2[l*I+i]=lsv-sv[l][i]-dsv1[l*I+i];
+      }
+    }
+#endif
+  }
+  L_1=L-1;
+  if (endmode==1 || endmode==3)
+  {
+    //v from u given f[l]
+    int hT=T/2;
+    double fbin=floor((f[0]+f[1])*hT)/T;
+    double omg=fbin*2*M_PI;
+    cdouble jomg=cdouble(0, omg);
+    for (int c=0; c<T; c++)
+    {
+      double t=c-hT;
+      cdouble rot=polar(1.0, omg*t);
+      for (int i=0; i<I; i++) v[i][c]=u[i][c*2]*rot;
+      for (int i=0; i<I; i++) dv[i][c]=rot*du[i][c*2]*cdouble(2.0)+jomg*v[i][c];
+    }
+
+    //compute -<s, v'> over the lth frame
+    cdouble* ls=&s[0]; for (int i=0; i<I; i++) sv[L_1][i]=-Inner(T, ls, dv[i]);
+
+    //compute <sr, v> over the lth frame
+    for (int i=0; i<I; i++) for (int m=0; m<M; m++) shv1[i][m]=Inner(T, ls, h[m], v[i]);
+    //memset(srv[L_1][0], 0, sizeof(cdouble)*I*N);
+    MultiplyXY(I, M, N, srv[L_1], shv1, A[0]);
+#ifdef ERROR_CHECK
+    //error check: <s', v>=-<s, v'>
+    if (ds)
+    {
+      cdouble* lds=&ds[0];
+      for (int i=0; i<I && L_1*I+1<36; i++)
+      {
+        cdouble lsv=Inner(T, lds, v[i]); //compute <s', v[i]>
+        //cdouble* ls=&s[l*T];
+        //cdouble lsv2=Inner(2*T, ls, dv[i]);
+        dsv1[L_1*I+i]=lsv-sv[L_1][i]; //i.e. <s', v[i]>=-<s, v[i]'>+dsv1[lI+i]
+      }
+
+      //error check: srv[l]*pq=<s',v>
+      for (int i=0; i<I && L_1*I+i<36; i++)
+      {
+        cdouble lsv=0;
+        for (int n=0; n<N; n++) lsv+=srv[L_1][i][n]*aita[n];
+        dsv2[L_1*I+i]=lsv-sv[L_1][i]-dsv1[L_1*I+i];
+      }
+    }
+#endif
+    L_1++;
+  }
+  if (endmode==2 || endmode==3)
+  {
+    //v from u given f[l]
+    int hT=T/2;
+    double fbin=floor((f[L-1]+f[L])*hT)/T;
+    double omg=fbin*2*M_PI;
+    cdouble jomg=cdouble(0, omg);
+    for (int c=0; c<T; c++)
+    {
+      double t=c-hT;
+      cdouble rot=polar(1.0, omg*t);
+      for (int i=0; i<I; i++) v[i][c]=u[i][c*2]*rot;
+      for (int i=0; i<I; i++) dv[i][c]=cdouble(2.0)*du[i][c*2]*rot+jomg*v[i][c];
+    }
+
+    //compute -<s, v'> over the lth frame
+    cdouble* ls=&s[(L-1)*T]; for (int i=0; i<I; i++) sv[L_1][i]=-Inner(T, ls, dv[i]);
+
+    //compute <sr, v> over the lth frame
+    for (int i=0; i<I; i++) for (int m=0; m<M; m++) shv1[i][m]=Inner(T, ls, h[m], v[i]);
+    //memset(srv[L_1][0], 0, sizeof(cdouble)*I*N);
+    MultiplyXY(I, M, N, srv[L_1], shv1, A[L-1]);
+#ifdef ERROR_CHECK
+    //error check: <s', v>=-<s, v'>
+    if (ds)
+    {
+      cdouble* lds=&ds[(L-1)*T];
+      for (int i=0; i<I && L_1*I+1<36; i++)
+      {
+        cdouble lsv=Inner(T, lds, v[i]); //compute <s', v[i]>
+        //cdouble* ls=&s[l*T];
+        //cdouble lsv2=Inner(2*T, ls, dv[i]);
+        dsv1[L_1*I+i]=lsv-sv[L_1][i]; //i.e. <s', v[i]>=-<s, v[i]'>+dsv1[lI+i]
+      }
+
+      //error check: srv[l]*pq=<s',v>
+      for (int i=0; i<I && L_1*I+i<36; i++)
+      {
+        cdouble lsv=0;
+        for (int n=0; n<N; n++) lsv+=srv[L_1][i][n]*aita[n];
+        dsv2[L_1*I+i]=lsv-sv[L_1][i]-dsv1[L_1*I+i];
+      }
+    }
+#endif
+      L_1++;
+  }
+
+  if (L_1*2*I==2*N) GECP(N, aita, srv[0], sv[0]);
+  else LSLinear(L_1*I, N, aita, srv[0], sv[0]);
+
+  delete mlist;
+}//DerivativePiecewise
+
+/*
+  function DerivativePiecewise2: Piecewise derivative algorithm in which the real and imaginary parts of
+  the exponent are modelled separately. In this implementation of the piecewise method the test
+  functions v are constructed from I "basic" (single-frame) test functions, each covering the same
+  period of 2T, by shifting these I functions by steps of T. A total number of (L-1)I test functions are
+  used.
+
+  In: s[LT+1]: waveform data
+      ds[LT+1]: derivative of s[LT], used only if ERROR_CHECK is defined.
+      L, T: number and length of pieces.
+      N: number of independent coefficients
+      h[M][T]: piecewise basis functions
+      A[L][M][Np]: L matrices that do coefficient mapping (real part) over the L pieces
+      B[L][M][Nq]: L matrices that do coefficient mapping (imaginary part) over the L pieces
+      u[I][2T}, du[I][2T]: base-band test functions
+      f[L+1]: reference frequencies at 0, T, ..., LT, only f[1]...f[L-1] are used
+      endmode: set to 1 or 3 to apply half-size testing over [0, T], to 2 or 3 to apply over [LT-T, LT]
+  Out: p[Np], q[Nq]: independent coefficients
+
+  No return value.
+*/
+void DerivativePiecewise2(int Np, double* p, int Nq, double* q, int L, double* f, int T, cdouble* s, double*** A, double*** B,
+  int M, double** h, int I, cdouble** u, cdouble** du, int endmode, cdouble* ds)
+{
+  MList* mlist=new MList;
+  int L_1=(endmode==0)?(L-1):((endmode==3)?(L+1):L);
+  cdouble** Allocate2L(cdouble, L_1, I, sv, mlist);
+  cdouble** Allocate2(cdouble, I, T*2, v);
+  cdouble** Allocate2(cdouble, I, T*2, dv);
+  //compute <sr, v>
+  cdouble*** Allocate3L(cdouble, L_1, I, Np, srav, mlist);
+  cdouble*** srbv;
+  if (Np==Nq && B==A) srbv=srav; else {Allocate3L(cdouble, L_1, I, Nq, srbv, mlist);} //same model for amplitude and phase
+  cdouble** Allocate2L(cdouble, I, M, shv1, mlist);
+  cdouble** Allocate2L(cdouble, I, M, shv2, mlist);
+
+  for (int l=0; l<L-1; l++)
+  {
+    //v from u given f[l]
+    double fbin=floor(f[l+1]*T*2)/(T*2.0);
+    double omg=fbin*2*M_PI;
+    cdouble jomg=cdouble(0, omg);
+    for (int c=0; c<T*2; c++)
+    {
+      double t=c-T;
+      cdouble rot=polar(1.0, omg*t);
+      for (int i=0; i<I; i++) v[i][c]=u[i][c]*rot;
+      for (int i=0; i<I; i++) dv[i][c]=du[i][c]*rot+jomg*v[i][c];
+    }
+
+    //compute -<s, v'> over the lth frame
+    cdouble* ls=&s[l*T]; for (int i=0; i<I; i++) sv[l][i]=-Inner(2*T, ls, dv[i]);
+
+    //compute <sr, v> over the lth frame
+    cdouble *ls1=&s[l*T], *ls2=&s[l*T+T];
+    for (int i=0; i<I; i++)
+      for (int m=0; m<M; m++)
+        shv1[i][m]=Inner(T, ls1, h[m], v[i]), shv2[i][m]=Inner(T, ls2, h[m], &v[i][T]);
+    memset(srav[l][0], 0, sizeof(cdouble)*I*Np);
+    MultiplyXY(I, M, Np, srav[l], shv1, A[l]);
+    MultiAddXY(I, M, Np, srav[l], shv2, A[l+1]);
+    if (srbv!=srav) //so that either B!=A or Np!=Nq
+    {
+      //memset(srbv[l][0], 0, sizeof(cdouble)*I*Nq);
+      MultiplyXY(I, M, Nq, srbv[l], shv1, B[l]);
+      MultiAddXY(I, M, Nq, srbv[l], shv2, B[l+1]);
+    }
+  }
+  L_1=L-1;
+  if (endmode==1 || endmode==3)
+  {
+    //v from u given f[l]
+    int hT=T/2;
+    double fbin=floor((f[0]+f[1])*hT)/T;
+    double omg=fbin*2*M_PI;
+    cdouble jomg=cdouble(0, omg);
+    for (int c=0; c<T; c++)
+    {
+      double t=c-hT;
+      cdouble rot=polar(1.0, omg*t);
+      for (int i=0; i<I; i++) v[i][c]=u[i][c*2]*rot;
+      for (int i=0; i<I; i++) dv[i][c]=rot*du[i][c*2]*cdouble(2.0)+jomg*v[i][c];
+    }
+
+    //compute -<s, v'> over the lth frame
+    cdouble* ls=&s[0]; for (int i=0; i<I; i++) sv[L_1][i]=-Inner(T, ls, dv[i]);
+
+    //compute <sr, v> over the lth frame
+    for (int i=0; i<I; i++) for (int m=0; m<M; m++) shv1[i][m]=Inner(T, ls, h[m], v[i]);
+    //memset(srav[L_1][0], 0, sizeof(cdouble)*I*Np);
+    MultiplyXY(I, M, Np, srav[L_1], shv1, A[0]);
+    if (srbv!=srav) {memset(srbv[L_1][0], 0, sizeof(cdouble)*I*Nq);	MultiplyXY(I, M, Nq, srbv[L_1], shv1, B[0]);}
+    L_1++;
+  }
+  if (endmode==2 || endmode==3)
+  {
+    //v from u given f[l]
+    int hT=T/2;
+    double fbin=floor((f[L-1]+f[L])*hT)/T;
+    double omg=fbin*2*M_PI;
+    cdouble jomg=cdouble(0, omg);
+    for (int c=0; c<T; c++)
+    {
+      double t=c-hT;
+      cdouble rot=polar(1.0, omg*t);
+      for (int i=0; i<I; i++) v[i][c]=u[i][c*2]*rot;
+      for (int i=0; i<I; i++) dv[i][c]=cdouble(2.0)*du[i][c*2]*rot+jomg*v[i][c];
+    }
+
+    //compute -<s, v'> over the lth frame
+    cdouble* ls=&s[(L-1)*T]; for (int i=0; i<I; i++) sv[L_1][i]=-Inner(T, ls, dv[i]);
+
+    //compute <sr, v> over the lth frame
+    for (int i=0; i<I; i++) for (int m=0; m<M; m++) shv1[i][m]=Inner(T, ls, h[m], v[i]);
+    memset(srav[L_1][0], 0, sizeof(cdouble)*I*Np);
+    MultiplyXY(I, M, Np, srav[L_1], shv1, A[L-1]);
+    if (srbv!=srav)
+    {
+      //memset(srbv[L_1][0], 0, sizeof(cdouble)*I*Nq);
+      MultiplyXY(I, M, Nq, srbv[L_1], shv1, B[L-1]);
+    }
+    L_1++;
+  }
+
+  //real implementation of <sr,v>aita=<s',v>
+  double** Allocate2L(double, L_1*I*2, Np+Nq, AM, mlist);
+  for (int l=0; l<L_1; l++) for (int i=0; i<I; i++)
+  {
+    int li=l*I+i, li_H=li+L_1*I;
+    for (int n=0; n<Np; n++)
+    {
+      AM[li][n]=srav[l][i][n].x;
+      AM[li_H][n]=srav[l][i][n].y;
+    }
+    for (int n=0; n<Nq; n++)
+    {
+      AM[li][Np+n]=-srbv[l][i][n].y;
+      AM[li_H][Np+n]=srbv[l][i][n].x;
+    }
+  }
+  //least-square solution of (srv)(aita)=(sv)
+  double* pq=new double[Np+Nq]; mlist->Add(pq, 1);
+  double* b=new double[2*L_1*I]; for (int i=0; i<L_1*I; i++) b[i]=sv[0][i].x, b[i+L_1*I]=sv[0][i].y;
+
+  if (L_1*2*I==Np+Nq) GECP(Np+Nq, pq, AM, b);
+  else LSLinear(2*L_1*I, Np+Nq, pq, AM, b);
+
+  memcpy(p, pq, sizeof(double)*Np); memcpy(q, &pq[Np], sizeof(double)*Nq);
+
+  delete mlist;
+}//DerivativePiecewise2
+
+/*
+  Error check: test that ds[LT] equals s[LT] times reconstructed R'. Notice that DA is D time A where D
+  is a pre-emphasis because p[Np] applies to log amplitude rather than its derivative.
+*/
+double testds_pqA(int Np, double* p, int Nq, double* q, int L, int T, cdouble* s, cdouble* ds, int M, double** h, double** dh, double*** DA, double*** B, cdouble* errds=0)
+{
+  double err=0, ene=0, *lamdax=new double[M*2], *lamday=&lamdax[M];
+  for (int l=0; l<L; l++)
+  {
+    MultiplyXy(M, Np, lamdax, DA[l], p);
+    MultiplyXy(M, Nq, lamday, B[l], q);
+    for (int t=0; t<T; t++)
+    {
+      double drtx=0; for (int m=0; m<M; m++) drtx+=lamdax[m]*h[m][t];
+      double drty=0; for (int m=0; m<M; m++) drty+=lamday[m]*h[m][t];
+      cdouble drt=cdouble(drtx, drty);
+      cdouble eds=ds[l*T+t]-s[l*T+t]*drt;
+      err+=~eds; ene+=~ds[l*T+t];
+      if (errds) errds[l*T+t]=eds;
+    }
+  }
+  delete[] lamdax;
+  return err/ene;
+}//testds_pqA
+
+/*
+  Error check: dsv1[I] tests that <s', v[I]> equals -<s, v[I]'>, dsv2[I] tests that <sr, v[I]>*pq=
+  <s',v[I]>
+*/
+void testdsv(cdouble* dsv1, cdouble* dsv2, int Np, double* p, int Nq, double* q, int TT, cdouble* dsl, int I, cdouble** vl, cdouble* svl, cdouble** sravl, cdouble** srbvl)
+{
+  for (int i=0; i<I; i++)
+  {
+    cdouble lsv=Inner(TT, dsl, vl[i]); //compute <s', v[i]>
+    //cdouble* ls=&s[l*T];
+    dsv1[i]=lsv-svl[i]; //i.e. <s', v[i]>=-<s, v[i]'>+dsv1[lI+i]
+    //sv[l][i]=lsv;
+  }
+  //error check: srv[l]*pq=<s',v>
+  for (int i=0; i<I; i++)
+  {
+    cdouble lsv=0;
+    for (int n=0; n<Np; n++) lsv+=sravl[i][n]*p[n];
+    for (int n=0; n<Nq; n++) lsv+=srbvl[i][n]*cdouble(0, q[n]);
+    dsv2[i]=lsv-svl[i]-dsv1[i];
+  }
+}//testdsv
+
+/*
+  Error check: tests A[MN]x[N1]=b[N1], returns square error
+*/
+double testlinearsystem(int M, int N, double** A, double* x, double* b)
+{
+  double err=0;
+  for (int m=0; m<M; m++)
+  {
+    double errli=Inner(N, A[m], x)-b[m];
+    err+=errli*errli;
+  }
+  return err;
+}//testlinearsystem
+
+/*
+  Error check: test the total square norm of <s, v>
+*/
+double testsv(int L, double* f, int T, cdouble* s, int I, cdouble** u, cdouble** du, int endmode)
+{
+  cdouble** Allocate2(cdouble, I, T*2, v);
+  cdouble** Allocate2(cdouble, I, T*2, dv);
+  double ene=0;
+  for (int l=0; l<L-1; l++)
+  {
+    //v from u given f[l]
+    setv(I, T*2, v, dv, f[l+1], u, du);
+    //compute -<s, v'> over the lth frame
+    cdouble* ls=&s[l*T];
+    for (int i=0; i<I; i++)
+    {
+      cdouble d=Inner(2*T, ls, v[i]);
+      ene+=~d;
+    }
+  }
+  if (endmode==1 || endmode==3)
+  {
+    //v from u given f[l]
+    setvhalf(I, T, v, dv, (f[0]+f[1])/2, u, du);
+    cdouble* ls=&s[0];
+    for (int i=0; i<I; i++)
+
+      ene+=~Inner(T, ls, v[i]);
+  }
+  if (endmode==2 || endmode==3)
+  {
+    //v from u given f[l]
+    setvhalf(I, T, v, dv, (f[L-1]+f[L])/2, u, du);
+    cdouble* ls=&s[(L-1)*T];
+    for (int i=0; i<I; i++)
+      ene+=~Inner(T, ls, v[i]);
+  }
+  DeAlloc2(v); DeAlloc2(dv);
+  return ene;
+}//testsv
+
+/*
+  function DerivativePiecewise3: Piecewise derivative algorithm in which the log amplitude and frequeny
+  are modeled separately as piecewise functions. In this implementation of the piecewise method the test
+  functions v are constructed from I "basic" (single-frame) test functions, each covering the same
+  period of 2T, by shifting these I functions by steps of T. A total number of (L-1)I test functions are
+  used.
+
+  In: s[LT+1]: waveform data
+      ds[LT+1]: derivative of s[LT], used only if ERROR_CHECK is defined.
+      L, T: number and length of pieces.
+      N: number of independent coefficients
+      h[M][T]: piecewise basis functions
+      dh[M][T]: derivative of h[M][T], used only if ERROR_CHECK is defined.
+      DA[L][M][Np]: L matrices that do coefficient mapping (real part) over the L pieces
+      B[L][M][Nq]: L matrices that do coefficient mapping (imaginary part) over the L pieces
+      u[I][2T}, du[I][2T]: base-band test functions
+      f[L+1]: reference frequencies at 0, T, ..., LT, only f[1]...f[L-1] are used
+      endmode: set to 1 or 3 to apply half-size testing over [0, T], to 2 or 3 to apply over [LT-T, LT]
+  Out: p[Np], q[Nq]: independent coefficients
+
+  No return value.
+*/
+void DerivativePiecewise3(int Np, double* p, int Nq, double* q, int L, double* f, int T, cdouble* s, double*** DA, double*** B,
+  int M, double** h, int I, cdouble** u, cdouble** du, int endmode, cdouble* ds, double** dh)
+{
+  MList* mlist=new MList;
+  int L_1=(endmode==0)?(L-1):((endmode==3)?(L+1):L);
+  cdouble** Allocate2L(cdouble, L_1, I, sv, mlist);
+  cdouble** Allocate2L(cdouble, I, T*2, v, mlist);
+  cdouble** Allocate2L(cdouble, I, T*2, dv, mlist);
+  //compute <sr, v>
+  cdouble*** Allocate3L(cdouble, L_1, I, Np, srav, mlist);
+  cdouble*** srbv;
+  if (Np==Nq && B==DA) srbv=srav; else {Allocate3L(cdouble, L_1, I, Nq, srbv, mlist);} //same model for amplitude and phase
+  cdouble** Allocate2L(cdouble, I, M, shv1, mlist);
+  cdouble** Allocate2L(cdouble, I, M, shv2, mlist);
+
+#ifdef ERROR_CHECK
+  cdouble dsv1in[128], dsv2in[128];
+#endif
+
+  for (int l=0; l<L-1; l++)
+  {
+    //v from u given f[l]
+    setv(I, T*2, v, dv, f[l+1], u, du);
+    //compute -<s, v'> over the lth frame
+    cdouble* ls=&s[l*T]; for (int i=0; i<I; i++) sv[l][i]=-Inner(2*T, ls, dv[i]);
+
+    //compute <sr, v> over the lth frame
+    cdouble *ls1=&s[l*T], *ls2=&s[l*T+T];
+    for (int i=0; i<I; i++)
+      for (int m=0; m<M; m++)
+        shv1[i][m]=Inner(T, ls1, h[m], v[i]), shv2[i][m]=Inner(T, ls2, h[m], &v[i][T]);
+    memset(srav[l][0], 0, sizeof(cdouble)*I*Np);
+    MultiplyXY(I, M, Np, srav[l], shv1, DA[l]);
+    MultiAddXY(I, M, Np, srav[l], shv2, DA[l+1]);
+    if (srbv!=srav) //so that either B!=A or Np!=Nq
+    {
+      MultiplyXY(I, M, Nq, srbv[l], shv1, B[l]);
+      MultiAddXY(I, M, Nq, srbv[l], shv2, B[l+1]);
+    }
+#ifdef ERROR_CHECK
+    //error check: <s', v>=-<s, v'> and srv[l]*pq=<s',v>
+    if (ds) testdsv(&dsv1in[l*I], &dsv2in[l*I], Np, p, Nq, q, T*2, &ds[l*T], I, v, sv[l], srav[l], srbv[l]);
+#endif
+  }
+  L_1=L-1;
+  if (endmode==1 || endmode==3)
+  {
+    //v from u given f[l]
+    setvhalf(I, T, v, dv, (f[0]+f[1])/2, u, du);
+    //compute -<s, v'> over the lth frame
+    cdouble* ls=&s[0]; for (int i=0; i<I; i++) sv[L_1][i]=-Inner(T, ls, dv[i]);
+    //compute <sr, v> over the lth frame
+    for (int i=0; i<I; i++) for (int m=0; m<M; m++) shv1[i][m]=Inner(T, ls, h[m], v[i]);
+    //memset(srav[L_1][0], 0, sizeof(cdouble)*I*Np);
+    MultiplyXY(I, M, Np, srav[L_1], shv1, DA[0]);
+    if (srbv!=srav) {memset(srbv[L_1][0], 0, sizeof(cdouble)*I*Nq);	MultiplyXY(I, M, Nq, srbv[L_1], shv1, B[0]);}
+#ifdef ERROR_CHECK
+    //error check: <s', v>=-<s, v'> and srv[l]*pq=<s',v>
+    if (ds) testdsv(&dsv1in[L_1*I], &dsv2in[L_1*I], Np, p, Nq, q, T, &ds[0], I, v, sv[L_1], srav[L_1], srbv[L_1]);
+#endif
+    L_1++;
+  }
+  if (endmode==2 || endmode==3)
+  {
+    //v from u given f[l]
+    setvhalf(I, T, v, dv, (f[L-1]+f[L])/2, u, du);
+    //compute -<s, v'> over the lth frame
+    cdouble* ls=&s[(L-1)*T]; for (int i=0; i<I; i++) sv[L_1][i]=-Inner(T, ls, dv[i]);
+    //compute <sr, v> over the lth frame
+    for (int i=0; i<I; i++) for (int m=0; m<M; m++) shv1[i][m]=Inner(T, ls, h[m], v[i]);
+    memset(srav[L_1][0], 0, sizeof(cdouble)*I*Np);
+    MultiplyXY(I, M, Np, srav[L_1], shv1, DA[L-1]);
+    if (srbv!=srav)	MultiplyXY(I, M, Nq, srbv[L_1], shv1, B[L-1]);
+#ifdef ERROR_CHECK
+    //error check: <s', v>=-<s, v'> and srv[l]*pq=<s',v>
+    if (ds) testdsv(&dsv1in[L_1*I], &dsv2in[L_1*I], Np, p, Nq, q, T, &ds[(L-1)*T], I, v, sv[L_1], srav[L_1], srbv[L_1]);
+#endif
+    L_1++;
+  }
+
+  //real implementation of <sr,v>aita=<s',v>
+  double** Allocate2L(double, L_1*I*2, Np+Nq, AM, mlist);
+  for (int l=0; l<L_1; l++) for (int i=0; i<I; i++)
+  {
+    int li=l*I+i, li_H=li+L_1*I;
+    for (int n=0; n<Np; n++)
+    {
+      AM[li][n]=srav[l][i][n].x;
+      AM[li_H][n]=srav[l][i][n].y;
+    }
+    for (int n=0; n<Nq; n++)
+    {
+      AM[li][Np+n]=-srbv[l][i][n].y;
+      AM[li_H][Np+n]=srbv[l][i][n].x;
+    }
+  }
+  //least-square solution of (srv)(aita)=(sv)
+  double* pq=new double[Np+Nq]; mlist->Add(pq, 1);
+  double* b=new double[2*L_1*I]; for (int i=0; i<L_1*I; i++) b[i]=sv[0][i].x, b[i+L_1*I]=sv[0][i].y; mlist->Add(b, 1);
+#ifdef ERROR_CHECK
+    //tests that AM is invariant to a constant shift of p
+    double errAM=0, errAM2=0, err1, err2;
+    for (int l=0; l<L_1*I; l++){double errli=0; for (int n=0; n<Np; n++) errli+=AM[l][n]; errAM+=errli*errli; errli=0; for (int n=0; n<Np; n+=2) errli+=AM[l][n]; errAM2+=errli*errli;}
+    //test square error of the input pq
+    if (ds)
+    {
+      memcpy(pq, p, sizeof(double)*Np); memcpy(&pq[Np], q, sizeof(double)*Nq);
+      err1=testlinearsystem(L_1*I*2, Np+Nq, AM, pq, b);
+    }
+    //test error of s'-sR where R is synthesized from the input pq
+    double errdsin, errdsvin; cdouble* edsin;
+    if (ds && dh)
+    {
+      edsin=new cdouble[L*T]; mlist->Add(edsin, 1);
+      errdsin=testds_pqA(Np, p, Nq, q, L, T, s, ds, M, h, dh, DA, B, edsin);
+      errdsvin=testsv(L, f, T, edsin, I, u, du, endmode);
+    }
+#endif
+  Alloc2L(L_1*I*2, Np+Nq-1, Am, mlist);
+  for (int l=0; l<L_1*I*2; l++) memcpy(Am[l], &AM[l][1], sizeof(double)*(Np+Nq-1));
+  pq[0]=0;
+  //if (L_1*2*I==Np+Nq) GECP(Np+Nq, pq, AM, b);
+  //else LSLinear(2*L_1*I, Np+Nq, pq, AM, b);
+  if (L_1*2*I==Np+Nq-1) GECP(Np+Nq-1, &pq[1], Am, b);
+  else LSLinear(2*L_1*I, Np+Nq-1, &pq[1], Am, b);
+#ifdef ERROR_CHECK
+    //test square error of output pq
+    if (ds) err2=testlinearsystem(L_1*I*2, Np+Nq, AM, pq, b);
+    //test error of s'-sR of the output pq
+    double errdsout, errdsvout; cdouble* edsout;
+    if (ds && dh)
+    {
+      edsout=new cdouble[L*T]; mlist->Add(edsout, 1);
+      errdsout=testds_pqA(Np, pq, Nq, &pq[Np], L, T, s, ds, M, h, dh, DA, B, edsout);
+      errdsvout=testsv(L, f, T, edsout, I, u, du, endmode);
+    }
+#endif
+  memcpy(p, pq, sizeof(double)*Np); memcpy(q, &pq[Np], sizeof(double)*Nq);
+
+  delete mlist;
+}//DerivativePiecewise3
+
+//initialization routines for the piecewise derivative method
+
+/*
+  function seth: set h[M] to a series of power functions.
+
+  In: M, T.
+  Out: h[M][T], where h[m] is power function of order m.
+
+  No return value. h is allocated anew and must be freed by caller.
+*/
+void seth(int M, int T, double**& h, MList* mlist)
+{
+ if (M<=0){h=0; return;}
+ Allocate2L(double, M, T, h, mlist);
+ double* hm=h[0]; for (int t=0; t<T; t++) hm[t]=1;
+ for (int m=1; m<M; m++)
+ {
+   hm=h[m]; for (int t=0; t<T; t++) hm[t]=pow(t*1.0, m);
+ }
+}//seth
+
+/*
+  function setdh: set dh[M] to the derivative of a series of power functions.
+
+  In: M, T.
+  Out: dh[M][T], where dh[m] is derivative of the power function of order m.
+
+  No return value. dh is allocated anew and must be freed by caller.
+*/
+void setdh(int M, int T, double**& dh, MList* mlist)
+{
+ if (M<=0){dh=0; return;}
+ Allocate2L(double, M, T, dh, mlist);
+ double* dhm=dh[0]; memset(dhm, 0, sizeof(double)*T);
+ if (M>1){dhm=dh[1]; for (int t=0; t<T; t++) dhm[t]=1;}
+ for (int m=2; m<M; m++)
+ {
+   dhm=dh[m]; for (int t=0; t<T; t++) dhm[t]=m*pow(t*1.0, m-1);
+ }
+}//setdh
+
+/*
+  function setdih: set dih[M] to the difference of the integral of a series of power functions.
+
+  In: M, I
+  Out: dih[M][I], where the accumulation of dih[m] is the integral of the power function of order m.
+
+  No return value. dih is allocated anew and must be freed by caller.
+*/
+void setdih(int M, int T, double**& dih, MList* mlist)
+{
+  if (M<=0){dih=0; return;}
+  Allocate2L(double, M, T, dih, mlist);
+  double* dihm=dih[0]; for (int t=0; t<T; t++) dihm[t]=1;
+  for (int m=1; m<M; m++)
+  {
+    dihm=dih[m]; for (int t=0; t<T; t++)	dihm[t]=(pow(t+1.0, m+1)-pow(t*1.0, m+1))/(m+1);
+  }
+}//setdih
+
+/*
+  function sshLinear: sets M and h[M] for the linear spline model
+
+  In: T
+  Out: M=2, h[2][T] filled out for linear spline model.
+
+  No return value. h is allocated anew and must be freed by caller.
+*/
+void sshLinear(int T, int& M, double** &h, MList* mlist)
+{
+  M=2; Allocate2L(double, M, T, h, mlist);
+  for (int t=0; t<T; t++) h[0][t]=1, h[1][t]=t;
+}//sshLinear
+
+/*
+  function sdihLinear: sets dih[M] for the linear spline model. For testing only.
+
+  In: T
+  Out: dih[2][T] filled out for linear spline model.
+
+  No return value. dih is allocated anew and must be freed by caller.
+*/
+void sdihLinear(int T, double**& dih, MList* mlist)
+{
+  Allocate2L(double, 2, T, dih, mlist);
+  for (int t=0; t<T; t++)	dih[0][t]=1, dih[1][t]=t+0.5;
+}//sdihLinear
+
+/*
+  function sshCubic: sets M and h[M] for cubic spline models.
+
+  In: T
+  Out: M=4 and h[M] filled out for cubic spline models, including cubic and cubic-Hermite.
+
+  No return value. h is allocated anew and must be freed by caller.
+*/
+void sshCubic(int T, int& M, double** &h, MList* mlist)
+{
+  M=4; Allocate2L(double, M, T, h, mlist);
+  for (int t=0; t<T; t++) h[3][t]=t*t*t, h[2][t]=t*t, h[1][t]=t, h[0][t]=1;
+}//sshCubic
+
+/*
+  function sdihCubic: sets dih[M] for cubic spline models.
+
+  In: T
+  Out: dih[4] filled out for cubic spline models.
+
+  No return value. dih is allocated anew and must be freed by caller.
+*/
+void sdihCubic(int T, double** &dih, MList* mlist)
+{
+  Allocate2L(double, 4, T, dih, mlist);
+  for (int t=0; t<T; t++)
+  {
+    dih[3][t]=t*(t*(t+1.5)+1)+0.25, dih[2][t]=t*(t+1)+1.0/3, dih[1][t]=t+0.5, dih[0][t]=1;
+  }
+}//sdihCubic*/
+
+/*
+  function ssALinearSpline: sets N and A[L] for the linear spline model
+
+  In: L, M, T
+  Out: N=L+1, A[L][M][N] filled out for the linear spline model
+
+  No return value. A is created anew and bust be freed by caller.
+*/
+void ssALinearSpline(int L, int T, int M, int& N, double*** &A, MList* mlist, int mode)
+{
+  N=L+1;
+  Allocate3L(double, L, M, N, A, mlist);
+  memset(A[0][0], 0, sizeof(double)*L*M*N);
+  double iT=1.0/T; for (int l=0; l<L; l++) A[l][0][l]=1, A[l][1][l]=-iT, A[l][1][l+1]=iT;
+}//ssALinearSpline
+
+/*
+  function ssLinearSpline: sets M, N, h and A for the linear spline model
+
+  In: L, M, T
+  Out: N and h[][] and A[][][] filled out for the linear spline model
+
+  No reutrn value. A and h are created anew and bust be freed by caller.
+*/
+void ssLinearSpline(int L, int T, int M, int &N, double** &h, double*** &A, MList* mlist, int mode)
+{
+  seth(M, T, h, mlist);
+  ssALinearSpline(L, T, M, N, A, mlist);
+}//ssLinearSpline
+
+/*
+  function ssACubicHermite: sets N and A[L] for cubic Hermite spline model
+
+  In: L, M, T
+  Out: N=2(L+1), A[L][M][N] filled out for the cubic Hermite spline
+
+  No return value. A is created anew and must be freed by caller.
+*/
+void ssACubicHermite(int L, int T, int M, int& N, double*** &A, MList* mlist, int mode)
+{
+  N=2*(L+1);
+  Allocate3L(double, L, M, N, A, mlist); memset(A[0][0], 0, sizeof(double)*L*M*N);
+  double iT=1.0/T, iT2=iT*iT, iT3=iT2*iT;
+  for (int l=0; l<L; l++)
+  {
+    A[l][3][2*l]=2*iT3; A[l][3][2*l+2]=-2*iT3; A[l][3][2*l+1]=A[l][3][2*l+3]=iT2;
+    A[l][2][2*l]=-3*iT2; A[l][2][2*l+1]=-2*iT; A[l][2][2*l+2]=3*iT2; A[l][2][2*l+3]=-iT;
+    A[l][1][2*l+1]=1;
+    A[l][0][2*l]=1;
+  }
+}//ssACubicHermite
+
+/*
+  function ssLinearSpline: sets M, N, h and A for the cubic Hermite spline model
+
+  In: L, M, T
+  Out: N and h[][] and A[][][] filled out for the cubic Hermite spline model
+
+  No reutrn value. A and h are created anew and bust be freed by caller.
+*/
+void ssCubicHermite(int L, int T, int M, int& N, double** &h, double*** &A, MList* mlist, int mode)
+{
+  seth(M, T, h, mlist);
+  ssACubicHermite(L, T, M, N, A, mlist);
+}//ssCubicHermite
+
+/*
+  function ssACubicSpline: sets N and A[L] for cubic spline model
+
+  In: L, M, T
+      mode: boundary mode of cubic spline, 0=natural, 1=quadratic run-out, 2=cubic run-out
+  Out: N=2(L+1), A[L][M][N] filled out for the cubic spline
+
+  No return value. A is created anew and must be freed by caller.
+*/
+void ssACubicSpline(int L, int T, int M, int& N, double*** &A, MList* mlist, int mode)
+{
+  N=L+1;
+  Allocate3L(double, L, M, N, A, mlist); memset(A[0][0], 0, sizeof(double)*L*M*N);
+  Alloc2(L+1, L+1, ML); memset(ML[0], 0, sizeof(double)*(L+1)*(L+1));
+  Alloc2(L+1, L+1, MR); memset(MR[0], 0, sizeof(double)*(L+1)*(L+1));
+  //fill in ML and MR. The only difference between various cubic splines are ML.
+  double _6iT2=6.0/(T*T);
+  ML[0][0]=ML[L][L]=1;
+  for (int l=1; l<L; l++) ML[l][l-1]=ML[l][l+1]=1, ML[l][l]=4,
+    MR[l][l-1]=MR[l][l+1]=_6iT2, MR[l][l]=-2*_6iT2;
+  if (mode==0){} //no more coefficients are needed for natural cubic spline
+  else if (mode==1) ML[0][1]=ML[L][L-1]=-1; //setting for quadratic run-out
+  else if (mode==2) ML[0][1]=ML[L][L-1]=-2, ML[0][2]=ML[L][L-2]=1; //setting for cubic run-out
+  GICP(L+1, ML);
+  double** MM=MultiplyXY(L+1, ML, ML, MR);
+  double iT=1.0/T;
+  Alloc2(4, 2, M42); M42[3][0]=-1.0/6/T, M42[3][1]=1.0/6/T, M42[2][0]=0.5, M42[2][1]=M42[0][0]=M42[0][1]=0, M42[1][0]=-T/3.0, M42[1][1]=-T/6.0;
+  for (int l=0; l<L; l++)
+  {
+    MultiplyXY(4, 2, N, A[l], M42, &MM[l]);
+    A[l][1][l]-=iT; A[l][1][l+1]+=iT; A[l][0][l]+=1;
+  }
+  DeAlloc2(ML); DeAlloc2(MR); DeAlloc2(M42);
+}//ssACubicSpline
+
+/*
+  function ssLinearSpline: sets M, N, h and A for the cubic spline model
+
+  In: L, M, T
+  Out: N and h[][] and A[][][] filled out for the cubic spline model
+
+  No reutrn value. A and h are created anew and bust be freed by caller.
+*/
+void ssCubicSpline(int L, int T, int M, int& N, double** &h, double*** &A, MList* mlist, int mode)
+{
+  seth(M, T, h, mlist);
+  ssACubicSpline(L, T, M, N, A, mlist, mode);
+}//ssCubicSpline
+
+/*
+  function setu: sets u[I+1] as base-band windowed Fourier atoms, whose frequencies come in the order of
+  0, 1, -1, 2, -2, 3, -3, 4, etc, in bins.
+
+  In: I, Wid: number and size of atoms to generate.
+      WinOrder: order (=vanishing moment) of window function to use (2=Hann, 4=Hann^2, etc.)
+  Out: u[I+1][Wid], du[I+1]{Wid]: the I+1 atoms and their derivatives.
+
+  No return value. u and du are created anew and must be freed by caller.
+*/
+void setu(int I, int Wid, cdouble**& u, cdouble**& du, int WinOrder, MList* mlist)
+{
+  Allocate2L(cdouble, I+1, Wid, u, mlist);
+  Allocate2L(cdouble, I+1, Wid, du, mlist);
+
+  double** wins=CosineWindows(WinOrder, Wid, (double**)0, 2);
+  double omg=2*M_PI/Wid; cdouble jomg=cdouble(0, omg);
+  for (int t=0; t<Wid; t++)
+  {
+    u[0][t]=wins[0][t], du[0][t]=wins[1][t];
+    int li=1;
+    for (int i=1; i<=I; i++)
+    {
+      cdouble rot=polar(1.0, li*omg*t);
+      u[i][t]=u[0][t]*rot; du[i][t]=du[0][t]*rot+jomg*li*u[i][t];
+      li=-li; if (li>0) li++;
+    }
+  }
+  DeAlloc2(wins);
+}//setu
+
+/*
+  function DerivativePiecewiseI: wrapper for DerivativePiecewise(), doing the initialization ,etc.
+
+  In: L, T: number and length of pieces
+      s[LT]: waveform signal
+      ds[LT]: derivative of s[LT], used only when ERROR_CHECK is defined.
+      f[L+1]: reference frequencies at knots
+      M: polynomial degree of piecewise approximation
+      SpecifyA, ssmode: pointer to a function that fills A[L], and mode argument to call it
+      WinOrder: order(=vanishing moment) of window used for constructing test functions
+      I: number of test functions per frame.
+      endmode: set to 1 or 3 to apply half-size frame over [0, T], to 2 or 3 to apply over [LT-T, LT]
+  Out: aita[N]: independent coefficients, where N is specified by SpecifyA.
+
+  No return vlue.
+*/
+void DerivativePiecewiseI(cdouble* aita, int L, double* f, int T, cdouble* s, int M,
+  void (*SpecifyA)(int L, int T, int M, int &N, double*** &A, MList* mlist, int mode), int ssmode,
+  int WinOrder, int I, int endmode, cdouble* ds)
+{
+  MList* mlist=new MList;
+  cdouble **u, **du;
+  setu(I, 2*T, u, du, WinOrder, mlist);
+
+  int N; double **h, ***A;
+  seth(M, T, h, mlist);
+  SpecifyA(L, T, M, N, A, mlist, ssmode);
+
+  DerivativePiecewise(N, aita, L, f, T, s, A, M, h, I, u, du, endmode, ds);
+  delete mlist;
+}//DerivativePiecewiseI
+
+/*
+  function DerivativePiecewiseII: wrapper for DerivativePiecewise2(), doing the initialization ,etc.
+  This models the derivative of log ampltiude and frequency as separate piecewise polynomials, the first
+  specified by SpecifyA, the second by SpecifyB.
+
+  In: L, T: number and length of pieces
+      s[LT]: waveform signal
+      ds[LT]: derivative of s[LT], used only when ERROR_CHECK is defined.
+      f[L+1]: reference frequencies at knots
+      M: polynomial degree of piecewise approximation
+      SpecifyA, ssAmode: pointer to a function that fills A[L], and mode argument to call it
+      SpecifyB, ssBmode: pointer to a function that fills B[L], and mode argument to call it
+      WinOrder: order(=vanishing moment) of window used for constructing test functions
+      I: number of test functions per frame.
+      endmode: set to 1 or 3 to apply half-size frame over [0, T], to 2 or 3 to apply over [LT-T, LT]
+  Out: p[Np], q[Nq]: independent coefficients, where Np and Nq are specified by SpecifyA and SpecifyB.
+
+  No reutrn value.
+*/
+void DerivativePiecewiseII(double* p, double* q, int L, double* f, int T, cdouble* s, int M,
+  void (*SpecifyA)(int L, int T, int M, int &N, double*** &A, MList* mlist, int mode), int ssAmode,
+  void (*SpecifyB)(int L, int T, int M, int &N, double*** &B, MList* mlist, int mode), int ssBmode,
+  int WinOrder, int I, int endmode, cdouble* ds)
+{
+  MList* mlist=new MList;
+  cdouble **u, **du;
+  setu(I, 2*T, u, du, WinOrder, mlist);
+
+  int Np, Nq;
+  double **h, ***A, ***B;
+  seth(M, T, h, mlist);
+  SpecifyA(L, T, M, Np, A, mlist, ssAmode);
+  SpecifyB(L, T, M, Nq, B, mlist, ssBmode);
+
+  DerivativePiecewise2(Np, p, Nq, q, L, f, T, s, A, B, M, h, I, u, du, endmode, ds);
+
+  delete mlist;
+}//DerivativePiecewiseII
+
+/*
+  function DerivativePiecewiseIII: wrapper for DerivativePiecewise3(), doing the initialization ,etc.
+  Notice that this time the log amplitude, rather than its derivative, is modeled as a piecewise
+  polynomial specified by SpecifyA.
+
+  In: L, T: number and length of pieces
+      s[LT]: waveform signal
+      ds[LT]: derivative of s[LT], used only when ERROR_CHECK is defined.
+      f[L+1]: reference frequencies at knots
+      M: polynomial degree of piecewise approximation
+      SpecifyA, ssAmode: pointer to a function that fills A[L], and mode argument to call it
+      SpecifyB, ssBmode: pointer to a function that fills B[L], and mode argument to call it
+      WinOrder: order(=vanishing moment) of window used for constructing test functions
+      I: number of test functions per frame.
+      endmode: set to 1 or 3 to apply half-size frame over [0, T], to 2 or 3 to apply over [LT-T, LT]
+  Out: p[Np], q[Nq]: independent coefficients, where Np and Nq are specified by SpecifyA and SpecifyB.
+
+  No reutrn value.
+*/
+void DerivativePiecewiseIII(double* p, double* q, int L, double* f, int T, cdouble* s, int M,
+  void (*SpecifyA)(int L, int T, int M, int &N, double*** &A, MList* mlist, int mode), int ssAmode,
+  void (*SpecifyB)(int L, int T, int M, int &N, double*** &B, MList* mlist, int mode), int ssBmode,
+  int WinOrder, int I, int endmode, cdouble* ds)
+{
+  MList* mlist=new MList;
+  int Np, Nq;
+  double **h, ***A, ***B, **dh=0;
+  cdouble **u, **du;
+  setu(I, T*2, u, du, WinOrder, mlist);
+  seth(M, T, h, mlist);
+  if (ds) setdh(M, T, dh, mlist);
+  SpecifyA(L, T, M, Np, A, mlist, ssAmode);
+  SpecifyB(L, T, M, Nq, B, mlist, ssBmode);
+  Alloc2L(M, M, DM, mlist);
+  memset(DM[0], 0, sizeof(double)*M*M); for (int m=0; m<M-1; m++) DM[m][m+1]=m+1;
+  double** DA=0;
+
+  for (int l=0; l<L; l++)
+  {
+    DA=MultiplyXY(M, M, Np, DA, DM, A[l], mlist);
+    Copy(M, Np, A[l], DA);
+  }
+
+  DerivativePiecewise3(Np, p, Nq, q, L, f, T, s, A, B, M, h, I, u, du, endmode, ds, dh);
+
+  delete mlist;
+}//DerivativePiecewiseIII
+
+/*
+  function AmpPhCorrectionExpA: model-preserving amplitude and phase correction in piecewise derivative
+  method.
+
+  In: aita[N]: inital independent coefficients
+      L, T: number and size of pieces
+      sre[LT]: waveform data
+      h[M][T], dih[M][T]: piecewise basis functions and their difference-integrals
+      A[L][M][N]: L coefficient mapping matrices
+      SpecifyA: pointer to the function used for constructing A
+      WinOrder: order(=vanishing moment) of window used for constructing test functions
+  Out: aita[N]: corrected independent coefficients
+       s2[LT]: reconstruct sinusoid BEFORE correction
+
+  Returns the estimate of phase angle at 0.
+*/
+double AmpPhCorrectionExpA(cdouble* s2, int N, cdouble* aita, int L, int T, cdouble* sre, int M, double** h, double** dih, double*** A,
+  void (*SpecifyA)(int L, int T, int M, int &N, double*** &A, MList* mlist, int mode), int WinOrder)
+{
+  MList* mlist=new MList;
+  //*amplitude and phase correction
+  //amplitude is done by updating p, i.e. Re(aita)
+  double *s2ph=new double[L+1]; mlist->Add(s2ph, 1);
+  double *phcor=new double[L+1]; mlist->Add(phcor, 1);
+  cdouble* lamda=new cdouble[M]; mlist->Add(lamda, 1);
+  double* lamdax=new double[M]; mlist->Add(lamdax, 1);
+  double* lamday=new double[M]; mlist->Add(lamday, 1);
+  {
+  double tmpph=0;
+  memset(s2ph, 0, sizeof(double)*(L+1));
+  s2ph[0]=tmpph;
+  for (int l=0; l<L; l++)
+  {
+    MultiplyXy(M, N, lamda, A[l], aita); for (int m=0; m<M; m++) lamdax[m]=lamda[m].x, lamday[m]=lamda[m].y;
+    SinusoidExpA(T, &s2[l*T], M, lamdax, lamday, h, dih, tmpph); s2ph[l+1]=tmpph;
+  }
+  double* win=new double[2*T+1]; CosineWindows(WinOrder, 2*T, &win, 1); mlist->Add(win, 1);
+  for (int l=1; l<L; l++)
+  {
+    cdouble inn=Inner(2*T, &sre[l*T-T], win, &s2[l*T-T])/Inner(2*T, &s2[l*T-T], win, &s2[l*T-T]);
+    cdouble loginn=log(inn);
+    if (SpecifyA==ssACubicHermite)
+    {
+      aita[l*2]+=loginn.x;
+      s2ph[l]+=loginn.y;
+      phcor[l]=loginn.y;
+      if (l==1) aita[0]+=loginn.x, phcor[0]=loginn.y, s2ph[0]+=loginn.y;
+      if (l==L-1) aita[L*2]+=loginn.x, phcor[L]=loginn.y, s2ph[L]+=loginn.y;
+    }
+    else
+    {
+      aita[l]+=loginn.x;
+      s2ph[l]+=loginn.y;
+      phcor[l]=loginn.y;
+      if (l==1)
+      {
+        inn=Inner(T, sre, &win[T], s2)/Inner(T, s2, &win[T], s2);
+        loginn=log(inn);
+        aita[0]+=loginn.x;
+        s2ph[0]+=loginn.y;
+        phcor[0]=loginn.y;
+      }
+      if (l==L-1)
+      {
+        inn=Inner(T, &sre[L*T-T], win, &s2[L*T-T])/Inner(T, &s2[L*T-T], win, &s2[L*T-T]);
+        loginn=log(inn);
+        aita[L]+=loginn.x;
+        s2ph[L]+=loginn.y;
+        phcor[L]=loginn.y;
+      }
+    }
+  }
+
+  for (int l=1; l<=L; l++)
+  {
+    int k=floor((phcor[l]-phcor[l-1])/(2*M_PI)+0.5);
+    if (k!=0)
+      phcor[l]+=2*M_PI*k;
+  }
+  //*
+  //now phcor[] contains phase corrector to be interpolated
+  double *b=new double[L], *zet=new double[L+1], *dzet=new double[L+1]; memset(zet, 0, sizeof(double)*(L+1)); memset(dzet, 0, sizeof(double)*(L+1));
+  mlist->Add(b, 1); mlist->Add(zet, 1); mlist->Add(dzet, 1);
+  double ihT[]={T, T/2.0*T, T/3.0*T*T, T/4.0*T*T*T};
+
+  Alloc2L(L, N, BB, mlist);
+  //prepare linear system (BB)(zet)=(b)
+  for (int l=0; l<L; l++)
+  {
+    MultiplyxY(N, 4, BB[l], ihT, A[l]);
+    b[l]=phcor[l+1]-phcor[l];
+  }
+  Alloc2L(L, L, copyA, mlist);
+  if (L+1==N)	for (int l=0; l<L; l++) memcpy(copyA[l], &BB[l][1], sizeof(double)*L);
+  else if (L+1==N/2) for (int l=0; l<L; l++) for (int k=0; k<L; k++) copyA[l][k]=BB[l][2*k+2];
+  double* copyb=Copy(L, b, mlist);
+  zet[0]=0; GECP(L, &zet[1], copyA, copyb);
+  if (L+1==N) for (int l=0; l<L; l++) memcpy(copyA[l], &BB[l][1], sizeof(double)*L);
+  else if (L+1==N/2) for (int l=0; l<L; l++) for (int k=0; k<L; k++) copyA[l][k]=BB[l][2*k+2];
+  Copy(L, copyb, b); for (int l=0; l<L; l++) copyb[l]-=BB[l][0];
+  dzet[0]=1; GECP(L, &dzet[1], copyA, copyb);
+
+#ifdef ERROR_CHECK
+    //Test that (BB)(zet)=b and (BB)(dzet)=b
+    double* bbzet=MultiplyXy(L, L+1, BB, zet, mlist);
+    MultiAdd(L, bbzet, bbzet, b, -1);
+    double err1=Inner(L, bbzet, bbzet);
+    double* bbdzet=MultiplyXy(L, L+1, BB, dzet, mlist);
+    MultiAdd(L, bbdzet, bbdzet, b, -1);
+    double err2=Inner(L, bbdzet, bbdzet);
+    MultiAdd(L+1, dzet, dzet, zet, -1);
+    //Test that (BB)dzet=0
+    MultiplyXy(L, L+1, bbdzet, BB, dzet);
+    double err3=Inner(L, bbzet, bbzet);
+#endif
+  //now that (zet)+(miu)(dzet) is the general solution to (BB)(zet)=b,
+  //	we look for (miu) that maximizes smoothness
+
+  double innuv=0, innvv=0, lmd0[4], lmdd[4], clmdd[4],
+    T2=T*T, T3=T2*T, T4=T3*T, T5=T4*T;
+  for (int l=0; l<L; l++)
+  {
+    MultiplyXy(4, L+1, lmd0, A[l], zet);
+    MultiplyXy(4, L+1, lmdd, A[l], dzet);
+    clmdd[1]=T*lmdd[1]+T2*lmdd[2]+T3*lmdd[3];
+    clmdd[2]=T2*lmdd[1]+(4.0/3)*T3*lmdd[2]+1.5*T4*lmdd[3];
+    clmdd[3]=T3*lmdd[1]+1.5*T4*lmdd[2]+1.8*T5*lmdd[3];
+    innuv+=Inner(3, &lmd0[1], &clmdd[1]);
+    innvv+=Inner(3, &lmdd[1], &clmdd[1]);
+  }
+  MultiAdd(L+1, zet, zet, dzet, -innuv/innvv);
+
+  if (SpecifyA==ssACubicHermite)
+    for (int l=0; l<=L; l++) aita[2*l].y+=zet[l];
+  else
+    for (int l=0; l<=L; l++) aita[l].y+=zet[l];
+  //*/
+  }
+  double result=s2ph[0];
+  delete mlist;
+  return result;
+}//AmpPhCorrectionExpA