| 
							- /*
 -     WDL - resample.cpp
 -     Copyright (C) 2010 and later Cockos Incorporated
 - 
 -     This software is provided 'as-is', without any express or implied
 -     warranty.  In no event will the authors be held liable for any damages
 -     arising from the use of this software.
 - 
 -     Permission is granted to anyone to use this software for any purpose,
 -     including commercial applications, and to alter it and redistribute it
 -     freely, subject to the following restrictions:
 - 
 -     1. The origin of this software must not be misrepresented; you must not
 -        claim that you wrote the original software. If you use this software
 -        in a product, an acknowledgment in the product documentation would be
 -        appreciated but is not required.
 -     2. Altered source versions must be plainly marked as such, and must not be
 -        misrepresented as being the original software.
 -     3. This notice may not be removed or altered from any source distribution.
 -       
 -     You may also distribute this software under the LGPL v2 or later.
 - 
 - */
 - 
 - #include "resample.h"
 - #include <math.h>
 - 
 - #include "denormal.h"
 - 
 - #ifndef PI
 - #define PI 3.1415926535897932384626433832795
 - #endif
 - 
 - class WDL_Resampler::WDL_Resampler_IIRFilter
 - {
 - public:
 -   WDL_Resampler_IIRFilter() 
 -   { 
 -     m_fpos=-1;
 -     Reset(); 
 -   }
 -   ~WDL_Resampler_IIRFilter()
 -   {
 -   }
 - 
 -   void Reset() 
 -   { 
 -     memset(m_hist,0,sizeof(m_hist)); 
 -   }
 - 
 -   void setParms(double fpos, double Q)
 -   {
 -     if (fabs(fpos-m_fpos)<0.000001) return;
 -     m_fpos=fpos;
 - 
 -     double pos = fpos * PI;
 -     double cpos=cos(pos);
 -     double spos=sin(pos);
 -     
 -     double alpha=spos/(2.0*Q);
 -     
 -     double sc=1.0/( 1 + alpha);
 -     m_b1 = (1-cpos) * sc;
 -     m_b2 = m_b0 = m_b1*0.5;
 -     m_a1 =  -2 * cpos * sc;
 -     m_a2 = (1-alpha)*sc;
 - 
 -   }
 - 
 -   void Apply(WDL_ResampleSample *in1, WDL_ResampleSample *out1, int ns, int span, int w)
 -   {
 -     double b0=m_b0,b1=m_b1,b2=m_b2,a1=m_a1,a2=m_a2;
 -     double *hist=m_hist[w];
 -     while (ns--)
 -     {
 -       double in=*in1;
 -       in1+=span;
 -       double out = (double) ( in*b0 + hist[0]*b1 + hist[1]*b2 - hist[2]*a1 - hist[3]*a2);
 -       hist[1]=hist[0]; hist[0]=in;
 -       hist[3]=hist[2]; *out1 = hist[2]=denormal_filter_double(out);
 - 
 -       out1+=span;
 -     }
 -   }
 - 
 - private:
 -   double m_fpos;
 -   double m_a1,m_a2;
 -   double m_b0,m_b1,m_b2;
 -   double m_hist[WDL_RESAMPLE_MAX_FILTERS*WDL_RESAMPLE_MAX_NCH][4];
 - };
 - 
 - 
 - void inline WDL_Resampler::SincSample(WDL_ResampleSample *outptr, const WDL_ResampleSample *inptr, double fracpos, int nch, const WDL_SincFilterSample *filter, int filtsz)
 - {
 -   const int oversize=m_lp_oversize;
 - 
 -   fracpos *= oversize;
 -   const int ifpos=(int)fracpos;
 -   filter += (oversize-ifpos) * filtsz;
 -   fracpos -= ifpos;
 - 
 -   int x;
 -   for (x = 0; x < nch; x ++)
 -   {
 -     double sum=0.0,sum2=0.0;
 -     const WDL_SincFilterSample *fptr2=filter;
 -     const WDL_SincFilterSample *fptr=fptr2 - filtsz;
 -     const WDL_ResampleSample *iptr=inptr+x;
 -     int i=filtsz/2;
 -     while (i--)
 -     {
 -       sum += fptr[0]*iptr[0]; 
 -       sum2 += fptr2[0]*iptr[0]; 
 -       sum += fptr[1]*iptr[nch]; 
 -       sum2 += fptr2[1]*iptr[nch]; 
 -       iptr+=nch*2;
 -       fptr+=2;
 -       fptr2+=2;
 -     }
 -     outptr[x]=sum*fracpos + sum2*(1.0-fracpos);
 -   }
 - 
 - }
 - 
 - void inline WDL_Resampler::SincSample1(WDL_ResampleSample *outptr, const WDL_ResampleSample *inptr, double fracpos, const WDL_SincFilterSample *filter, int filtsz)
 - {
 -   const int oversize=m_lp_oversize;
 -   fracpos *= oversize;
 -   const int ifpos=(int)fracpos;
 -   fracpos -= ifpos;
 - 
 -   double sum=0.0,sum2=0.0;
 -   const WDL_SincFilterSample *fptr2=filter + (oversize-ifpos) * filtsz;
 -   const WDL_SincFilterSample *fptr=fptr2 - filtsz;
 -   const WDL_ResampleSample *iptr=inptr;
 -   int i=filtsz/2;
 -   while (i--)
 -   {
 -     sum += fptr[0]*iptr[0]; 
 -     sum2 += fptr2[0]*iptr[0];
 -     sum += fptr[1]*iptr[1]; 
 -     sum2 += fptr2[1]*iptr[1];
 -     iptr+=2;
 -     fptr+=2;
 -     fptr2+=2;
 -   }
 -   outptr[0]=sum*fracpos+sum2*(1.0-fracpos);
 - }
 - 
 - void inline WDL_Resampler::SincSample2(WDL_ResampleSample *outptr, const WDL_ResampleSample *inptr, double fracpos, const WDL_SincFilterSample *filter, int filtsz)
 - {
 -   const int oversize=m_lp_oversize;
 -   fracpos *= oversize;
 -   const int ifpos=(int)fracpos;
 -   fracpos -= ifpos;
 - 
 -   const WDL_SincFilterSample *fptr2=filter + (oversize-ifpos) * filtsz;
 -   const WDL_SincFilterSample *fptr=fptr2 - filtsz;
 - 
 -   double sum=0.0;
 -   double sum2=0.0;
 -   double sumb=0.0;
 -   double sum2b=0.0;
 -   const WDL_ResampleSample *iptr=inptr;
 -   int i=filtsz/2;
 -   while (i--)
 -   {
 -     sum += fptr[0]*iptr[0];
 -     sum2 += fptr[0]*iptr[1];
 -     sumb += fptr2[0]*iptr[0];
 -     sum2b += fptr2[0]*iptr[1];
 -     sum += fptr[1]*iptr[2];
 -     sum2 += fptr[1]*iptr[3];
 -     sumb += fptr2[1]*iptr[2];
 -     sum2b += fptr2[1]*iptr[3];
 -     iptr+=4;
 -     fptr+=2;
 -     fptr2+=2;
 -   }
 -   outptr[0]=sum*fracpos + sumb*(1.0-fracpos);
 -   outptr[1]=sum2*fracpos + sum2b*(1.0-fracpos);
 - 
 - }
 - 
 - 
 - 
 - WDL_Resampler::WDL_Resampler(int initialinputbuffersize)
 - {
 -   m_filterq=0.707f;
 -   m_filterpos=0.693f; // .792 ?
 - 
 -   m_sincoversize=0;
 -   m_lp_oversize=1; 
 -   m_sincsize=0;
 -   m_filtercnt=1;
 -   m_interp=true;
 -   m_feedmode=false;
 - 
 -   m_filter_coeffs_size=0; 
 -   m_sratein=44100.0; 
 -   m_srateout=44100.0; 
 -   m_ratio=1.0; 
 -   m_filter_ratio=-1.0; 
 -   m_iirfilter=0;
 -   if (initialinputbuffersize>0)
 - 	m_rsinbuf.Resize(initialinputbuffersize);
 -   Reset(); 
 - }
 - 
 - WDL_Resampler::~WDL_Resampler()
 - {
 -   delete m_iirfilter;
 - }
 - 
 - void WDL_Resampler::Reset(double fracpos)
 - {
 -   m_last_requested=0;
 -   m_filtlatency=0;
 -   m_fracpos=fracpos; 
 -   m_samples_in_rsinbuf=0; 
 -   if (m_iirfilter) m_iirfilter->Reset();   
 - }
 - 
 - void WDL_Resampler::SetMode(bool interp, int filtercnt, bool sinc, int sinc_size, int sinc_interpsize)
 - {
 -   m_sincsize = sinc && sinc_size>= 4 ? sinc_size > 8192 ? 8192 : (sinc_size&~1) : 0;
 -   m_sincoversize = m_sincsize  ? (sinc_interpsize<= 1 ? 1 : sinc_interpsize>=8192 ? 8192 : sinc_interpsize) : 1;
 - 
 -   m_filtercnt = m_sincsize ? 0 : (filtercnt<=0?0 : filtercnt >= WDL_RESAMPLE_MAX_FILTERS ? WDL_RESAMPLE_MAX_FILTERS : filtercnt);
 -   m_interp=interp && !m_sincsize;
 - //  char buf[512];
 - //  sprintf(buf,"setting interp=%d, filtercnt=%d, sinc=%d,%d\n",m_interp,m_filtercnt,m_sincsize,m_sincoversize);
 - //  OutputDebugString(buf);
 - 
 -   if (!m_sincsize) 
 -   {
 -     m_filter_coeffs.Resize(0);
 -     m_filter_coeffs_size=0;
 -   }
 -   if (!m_filtercnt) 
 -   {
 -     delete m_iirfilter;
 -     m_iirfilter=0;
 -   }
 - }
 - 
 - void WDL_Resampler::SetRates(double rate_in, double rate_out) 
 - {
 -   if (rate_in<1.0) rate_in=1.0;
 -   if (rate_out<1.0) rate_out=1.0;
 -   if (rate_in != m_sratein || rate_out != m_srateout)
 -   {
 -     m_sratein=rate_in; 
 -     m_srateout=rate_out;  
 -     m_ratio=m_sratein / m_srateout;
 -   }
 - }
 - 
 - 
 - void WDL_Resampler::BuildLowPass(double filtpos) // only called in sinc modes
 - {
 -   const int wantsize=m_sincsize;
 -   const int wantinterp=m_sincoversize;
 - 
 -   if (m_filter_ratio!=filtpos || 
 -       m_filter_coeffs_size != wantsize ||
 -       m_lp_oversize != wantinterp)
 -   {
 -     m_lp_oversize = wantinterp;
 -     m_filter_ratio=filtpos;
 - 
 -     // build lowpass filter
 -     const int allocsize = wantsize*(m_lp_oversize+1);
 -     WDL_SincFilterSample *cfout=m_filter_coeffs.Resize(allocsize);
 -     if (m_filter_coeffs.GetSize()==allocsize)
 -     {
 -       m_filter_coeffs_size=wantsize;
 - 
 -       const double dwindowpos = 2.0 * PI/(double)wantsize;
 -       const double dsincpos  = PI * filtpos; // filtpos is outrate/inrate, i.e. 0.5 is going to half rate
 -       const int hwantsize=wantsize/2;
 - 
 -       double filtpower=0.0;
 -       WDL_SincFilterSample *ptrout = cfout;
 -       int slice;
 -       for (slice=0;slice<=wantinterp;slice++)
 -       {
 -         const double frac = slice / (double)wantinterp;
 -         const int center_x = slice == 0 ? hwantsize : slice == wantinterp ? hwantsize-1 : -1;
 - 
 -         int x;
 -         for (x=0;x<wantsize;x++)
 -         {          
 -           if (x==center_x) 
 -           {
 -             // we know this will be 1.0
 -             *ptrout++ = 1.0;
 -           }
 -           else
 -           {
 -             const double xfrac = frac + x;
 -             const double windowpos = dwindowpos * xfrac;
 -             const double sincpos = dsincpos * (xfrac - hwantsize);
 - 
 -             // blackman-harris * sinc
 -             const double val = (0.35875 - 0.48829 * cos(windowpos) + 0.14128 * cos(2*windowpos) - 0.01168 * cos(3*windowpos)) * sin(sincpos) / sincpos; 
 -             if (slice<wantinterp) filtpower+=val;        
 -             *ptrout++ = (WDL_SincFilterSample)val;
 -           }
 - 
 -         }
 -       }
 - 
 -       filtpower = wantinterp/(filtpower+1.0);
 -       int x;
 -       for (x = 0; x < allocsize; x ++) 
 -       {
 -         cfout[x] = (WDL_SincFilterSample) (cfout[x]*filtpower);
 -       }
 -     }
 -     else m_filter_coeffs_size=0;
 - 
 -   }
 - }
 - 
 - double WDL_Resampler::GetCurrentLatency() 
 - { 
 -   double v=((double)m_samples_in_rsinbuf-m_filtlatency)/m_sratein;
 -   
 -   if (v<0.0)v=0.0;
 -   return v;
 - }
 - 
 - int WDL_Resampler::ResamplePrepare(int out_samples, int nch, WDL_ResampleSample **inbuffer) 
 - {   
 -   if (nch > WDL_RESAMPLE_MAX_NCH || nch < 1) return 0;
 - 
 -   int fsize=0;
 -   if (m_sincsize>1) fsize = m_sincsize;
 - 
 -   int hfs=fsize/2;
 -   if (hfs>1 && m_samples_in_rsinbuf<hfs-1)
 -   {
 -     m_filtlatency+=hfs-1 - m_samples_in_rsinbuf;
 - 
 -     m_samples_in_rsinbuf=hfs-1;
 - 
 -     if (m_samples_in_rsinbuf>0)
 -     {      
 -       WDL_ResampleSample *p = m_rsinbuf.Resize(m_samples_in_rsinbuf*nch,false);
 -       memset(p,0,sizeof(WDL_ResampleSample)*m_rsinbuf.GetSize());
 -     }
 -   }
 - 
 -   int sreq = 0;
 -     
 -   if (!m_feedmode) sreq = (int)(m_ratio * out_samples) + 4 + fsize - m_samples_in_rsinbuf;
 -   else sreq = out_samples;
 - 
 -   if (sreq<0)sreq=0;
 -   
 - again:
 -   m_rsinbuf.Resize((m_samples_in_rsinbuf+sreq)*nch,false);
 - 
 -   int sz = m_rsinbuf.GetSize()/(nch?nch:1) - m_samples_in_rsinbuf;
 -   if (sz!=sreq)
 -   {
 -     if (sreq>4 && !sz)
 -     {
 -       sreq/=2;
 -       goto again; // try again with half the size
 -     }
 -     // todo: notify of error?
 -     sreq=sz;
 -   }
 - 
 -   *inbuffer = m_rsinbuf.Get() + m_samples_in_rsinbuf*nch;
 - 
 -   m_last_requested=sreq;
 -   return sreq;
 - }
 - 
 - 
 - 
 - int WDL_Resampler::ResampleOut(WDL_ResampleSample *out, int nsamples_in, int nsamples_out, int nch)
 - {
 -   if (nch > WDL_RESAMPLE_MAX_NCH || nch < 1) return 0;
 - 
 -   if (m_filtercnt>0)
 -   {
 -     if (m_ratio > 1.0 && nsamples_in > 0) // filter input
 -     {
 -       if (!m_iirfilter) m_iirfilter = new WDL_Resampler_IIRFilter;
 - 
 -       int n=m_filtercnt;
 -       m_iirfilter->setParms((1.0/m_ratio)*m_filterpos,m_filterq);
 - 
 -       WDL_ResampleSample *buf=(WDL_ResampleSample *)m_rsinbuf.Get() + m_samples_in_rsinbuf*nch;
 -       int a,x;
 -       int offs=0;
 -       for (x=0; x < nch; x ++)
 -         for (a = 0; a < n; a ++)
 -           m_iirfilter->Apply(buf+x,buf+x,nsamples_in,nch,offs++);
 -     }
 -   }
 - 
 -   // prevent the caller from corrupting the internal state
 -   m_samples_in_rsinbuf += nsamples_in < m_last_requested ? nsamples_in : m_last_requested; 
 - 
 -   int rsinbuf_availtemp = m_samples_in_rsinbuf;
 - 
 -   if (nsamples_in < m_last_requested) // flush out to ensure we can deliver
 -   {
 -     int fsize=(m_last_requested-nsamples_in)*2 + m_sincsize*2;
 - 
 -     int alloc_size=(m_samples_in_rsinbuf+fsize)*nch;
 -     WDL_ResampleSample *zb=m_rsinbuf.Resize(alloc_size,false);
 -     if (m_rsinbuf.GetSize()==alloc_size)
 -     {
 -       memset(zb+m_samples_in_rsinbuf*nch,0,fsize*nch*sizeof(WDL_ResampleSample));
 -       rsinbuf_availtemp = m_samples_in_rsinbuf+fsize;
 -     }
 -   }
 - 
 -   int ret=0;
 -   double srcpos=m_fracpos;
 -   double drspos = m_ratio;
 -   WDL_ResampleSample *localin = m_rsinbuf.Get();
 - 
 -   WDL_ResampleSample *outptr=out;
 - 
 -   int ns=nsamples_out;
 - 
 -   int outlatadj=0;
 - 
 -   if (m_sincsize) // sinc interpolating
 -   {
 -     if (m_ratio > 1.0) BuildLowPass(1.0 / (m_ratio*1.03));
 -     else BuildLowPass(1.0);
 - 
 -     int filtsz=m_filter_coeffs_size;
 -     int filtlen = rsinbuf_availtemp - filtsz;
 -     outlatadj=filtsz/2-1;
 -     WDL_SincFilterSample *filter=m_filter_coeffs.Get();   
 - 
 -     if (nch == 1)
 -     {
 -       while (ns--)
 -       {
 -         int ipos = (int)srcpos;
 - 
 -         if (ipos >= filtlen-1)  break; // quit decoding, not enough input samples
 - 
 -         SincSample1(outptr,localin + ipos,srcpos-ipos,filter,filtsz);
 -         outptr ++;
 -         srcpos+=drspos;
 -         ret++;
 -       }
 -     }
 -     else if (nch==2)
 -     {
 -       while (ns--)
 -       {
 -         int ipos = (int)srcpos;
 - 
 -         if (ipos >= filtlen-1)  break; // quit decoding, not enough input samples
 - 
 -         SincSample2(outptr,localin + ipos*2,srcpos-ipos,filter,filtsz);
 -         outptr+=2;
 -         srcpos+=drspos;
 -         ret++;
 -       }
 -     }
 -     else
 -     {
 -       while (ns--)
 -       {
 -         int ipos = (int)srcpos;
 - 
 -         if (ipos >= filtlen-1)  break; // quit decoding, not enough input samples
 - 
 -         SincSample(outptr,localin + ipos*nch,srcpos-ipos,nch,filter,filtsz);
 -         outptr += nch;
 -         srcpos+=drspos;
 -         ret++;
 -       }
 -     }
 -   }
 -   else if (!m_interp) // point sampling
 -   {
 -     if (nch == 1)
 -     {
 -       while (ns--)
 -       {
 -         int ipos = (int)srcpos;
 -         if (ipos >= rsinbuf_availtemp)  break; // quit decoding, not enough input samples
 - 
 -         *outptr++ = localin[ipos];
 -         srcpos+=drspos;
 -         ret++;
 -       }
 -     }
 -     else if (nch == 2)
 -     {
 -       while (ns--)
 -       {
 -         int ipos = (int)srcpos;
 -         if (ipos >= rsinbuf_availtemp)  break; // quit decoding, not enough input samples
 - 
 -         ipos+=ipos;
 - 
 -         outptr[0] = localin[ipos];
 -         outptr[1] = localin[ipos+1];
 -         outptr+=2;
 -         srcpos+=drspos;
 -         ret++;
 -       }
 -     }
 -     else
 -       while (ns--)
 -       {
 -         int ipos = (int)srcpos;
 -         if (ipos >= rsinbuf_availtemp)  break; // quit decoding, not enough input samples
 -     
 -         memcpy(outptr,localin + ipos*nch,nch*sizeof(WDL_ResampleSample));
 -         outptr += nch;
 -         srcpos+=drspos;
 -         ret++;
 -       }
 -   }
 -   else // linear interpolation
 -   {
 -     if (nch == 1)
 -     {
 -       while (ns--)
 -       {
 -         int ipos = (int)srcpos;
 -         double fracpos=srcpos-ipos; 
 - 
 -         if (ipos >= rsinbuf_availtemp-1) 
 -         {
 -           break; // quit decoding, not enough input samples
 -         }
 - 
 -         double ifracpos=1.0-fracpos;
 -         WDL_ResampleSample *inptr = localin + ipos;
 -         *outptr++ = inptr[0]*(ifracpos) + inptr[1]*(fracpos);
 -         srcpos+=drspos;
 -         ret++;
 -       }
 -     }
 -     else if (nch == 2)
 -     {
 -       while (ns--)
 -       {
 -         int ipos = (int)srcpos;
 -         double fracpos=srcpos-ipos; 
 - 
 -         if (ipos >= rsinbuf_availtemp-1) 
 -         {
 -           break; // quit decoding, not enough input samples
 -         }
 - 
 -         double ifracpos=1.0-fracpos;
 -         WDL_ResampleSample *inptr = localin + ipos*2;
 -         outptr[0] = inptr[0]*(ifracpos) + inptr[2]*(fracpos);
 -         outptr[1] = inptr[1]*(ifracpos) + inptr[3]*(fracpos);
 -         outptr += 2;
 -         srcpos+=drspos;
 -         ret++;
 -       }
 -     }
 -     else
 -     {
 -       while (ns--)
 -       {
 -         int ipos = (int)srcpos;
 -         double fracpos=srcpos-ipos; 
 - 
 -         if (ipos >= rsinbuf_availtemp-1) 
 -         {
 -           break; // quit decoding, not enough input samples
 -         }
 - 
 -         double ifracpos=1.0-fracpos;
 -         int ch=nch;
 -         WDL_ResampleSample *inptr = localin + ipos*nch;
 -         while (ch--)
 -         {
 -           *outptr++ = inptr[0]*(ifracpos) + inptr[nch]*(fracpos);
 -           inptr++;
 -         }
 -         srcpos+=drspos;
 -         ret++;
 -       }
 -     }
 -   }
 - 
 - 
 -   if (m_filtercnt>0)
 -   {
 -     if (m_ratio < 1.0 && ret>0) // filter output
 -     {
 -       if (!m_iirfilter) m_iirfilter = new WDL_Resampler_IIRFilter;
 -       int n=m_filtercnt;
 -       m_iirfilter->setParms(m_ratio*m_filterpos,m_filterq);
 - 
 -       int x,a;
 -       int offs=0;
 -       for (x=0; x < nch; x ++)
 -         for (a = 0; a < n; a ++)
 -           m_iirfilter->Apply(out+x,out+x,ret,nch,offs++);
 -     }
 -   }
 - 
 -   
 - 
 -   if (ret>0 && rsinbuf_availtemp>m_samples_in_rsinbuf) // we had to pad!!
 -   {
 -     // check for the case where rsinbuf_availtemp>m_samples_in_rsinbuf, decrease ret down to actual valid samples
 -     double adj=(srcpos-m_samples_in_rsinbuf + outlatadj) / drspos;
 -     if (adj>0)
 -     {
 -       ret -= (int) (adj + 0.5);
 -       if (ret<0)ret=0;
 -     }
 -   }
 - 
 -   int isrcpos=(int)srcpos;
 -   if (isrcpos > m_samples_in_rsinbuf) isrcpos=m_samples_in_rsinbuf;
 -   m_fracpos = srcpos - isrcpos;
 -   m_samples_in_rsinbuf -= isrcpos;
 -   if (m_samples_in_rsinbuf <= 0) m_samples_in_rsinbuf=0;
 -   else
 -     memmove(localin, localin + isrcpos*nch,m_samples_in_rsinbuf*sizeof(WDL_ResampleSample)*nch);
 - 
 - 
 -   return ret;
 - }
 
 
  |