Initial git commit

This commit is contained in:
xenakios
2017-11-13 17:06:08 +02:00
commit d7ca59b90a
36 changed files with 8224 additions and 0 deletions

166
Source/WDL/denormal.h Normal file
View File

@ -0,0 +1,166 @@
#ifndef _WDL_DENORMAL_H_
#define _WDL_DENORMAL_H_
typedef struct
{
#ifdef __ppc__ // todo: other big endian platforms...
unsigned int hw;
unsigned int lw;
#else
unsigned int lw;
unsigned int hw;
#endif
} WDL_DenormalTwoInts;
typedef union { double fl; WDL_DenormalTwoInts w; } WDL_DenormalDoubleAccess;
typedef union { float fl; unsigned int w; } WDL_DenormalFloatAccess;
// note: the _aggressive versions filter out anything less than around 1.0e-16 or so (approximately) to 0.0, including -0.0 (becomes 0.0)
// note: new! the _aggressive versions also filter inf and NaN to 0.0
#ifdef __cplusplus
#define WDL_DENORMAL_INLINE inline
#elif defined(_MSC_VER)
#define WDL_DENORMAL_INLINE __inline
#else
#define WDL_DENORMAL_INLINE
#endif
#define WDL_DENORMAL_DOUBLE_HW(a) (((const WDL_DenormalDoubleAccess*)(a))->w.hw)
#define WDL_DENORMAL_DOUBLE_LW(a) (((const WDL_DenormalDoubleAccess*)(a))->w.lw)
#define WDL_DENORMAL_FLOAT_W(a) (((const WDL_DenormalFloatAccess*)(a))->w)
#define WDL_DENORMAL_DOUBLE_HW_NC(a) (((WDL_DenormalDoubleAccess*)(a))->w.hw)
#define WDL_DENORMAL_DOUBLE_LW_NC(a) (((WDL_DenormalDoubleAccess*)(a))->w.lw)
#define WDL_DENORMAL_FLOAT_W_NC(a) (((WDL_DenormalFloatAccess*)(a))->w)
#define WDL_DENORMAL_DOUBLE_AGGRESSIVE_CUTOFF 0x3cA00000 // 0x3B8000000 maybe instead? that's 10^-5 smaller or so
#define WDL_DENORMAL_FLOAT_AGGRESSIVE_CUTOFF 0x25000000
static double WDL_DENORMAL_INLINE denormal_filter_double(double a)
{
return (WDL_DENORMAL_DOUBLE_HW(&a)&0x7ff00000) ? a : 0.0;
}
static double WDL_DENORMAL_INLINE denormal_filter_double2(double a)
{
return ((WDL_DENORMAL_DOUBLE_HW(&a)+0x100000)&0x7ff00000) > 0x100000 ? a : 0.0;
}
static double WDL_DENORMAL_INLINE denormal_filter_double_aggressive(double a)
{
return ((WDL_DENORMAL_DOUBLE_HW(&a)+0x100000)&0x7ff00000) >= WDL_DENORMAL_DOUBLE_AGGRESSIVE_CUTOFF ? a : 0.0;
}
static float WDL_DENORMAL_INLINE denormal_filter_float(float a)
{
return (WDL_DENORMAL_FLOAT_W(&a)&0x7f800000) ? a : 0.0f;
}
static float WDL_DENORMAL_INLINE denormal_filter_float2(float a)
{
return ((WDL_DENORMAL_FLOAT_W(&a)+0x800000)&0x7f800000) > 0x800000 ? a : 0.0f;
}
static float WDL_DENORMAL_INLINE denormal_filter_float_aggressive(float a)
{
return ((WDL_DENORMAL_FLOAT_W(&a)+0x800000)&0x7f800000) >= WDL_DENORMAL_FLOAT_AGGRESSIVE_CUTOFF ? a : 0.0f;
}
static void WDL_DENORMAL_INLINE denormal_fix_double(double *a)
{
if (!(WDL_DENORMAL_DOUBLE_HW(a)&0x7ff00000)) *a=0.0;
}
static void WDL_DENORMAL_INLINE denormal_fix_double_aggressive(double *a)
{
if (((WDL_DENORMAL_DOUBLE_HW(a)+0x100000)&0x7ff00000) < WDL_DENORMAL_DOUBLE_AGGRESSIVE_CUTOFF) *a=0.0;
}
static void WDL_DENORMAL_INLINE denormal_fix_float(float *a)
{
if (!(WDL_DENORMAL_FLOAT_W(a)&0x7f800000)) *a=0.0f;
}
static void WDL_DENORMAL_INLINE denormal_fix_float_aggressive(float *a)
{
if (((WDL_DENORMAL_FLOAT_W(a)+0x800000)&0x7f800000) < WDL_DENORMAL_FLOAT_AGGRESSIVE_CUTOFF) *a=0.0f;
}
#ifdef __cplusplus // automatic typed versions (though one should probably use the explicit versions...
static double WDL_DENORMAL_INLINE denormal_filter(double a)
{
return (WDL_DENORMAL_DOUBLE_HW(&a)&0x7ff00000) ? a : 0.0;
}
static double WDL_DENORMAL_INLINE denormal_filter_aggressive(double a)
{
return ((WDL_DENORMAL_DOUBLE_HW(&a)+0x100000)&0x7ff00000) >= WDL_DENORMAL_DOUBLE_AGGRESSIVE_CUTOFF ? a : 0.0;
}
static float WDL_DENORMAL_INLINE denormal_filter(float a)
{
return (WDL_DENORMAL_FLOAT_W(&a)&0x7f800000) ? a : 0.0f;
}
static float WDL_DENORMAL_INLINE denormal_filter_aggressive(float a)
{
return ((WDL_DENORMAL_FLOAT_W(&a)+0x800000)&0x7f800000) >= WDL_DENORMAL_FLOAT_AGGRESSIVE_CUTOFF ? a : 0.0f;
}
static void WDL_DENORMAL_INLINE denormal_fix(double *a)
{
if (!(WDL_DENORMAL_DOUBLE_HW(a)&0x7ff00000)) *a=0.0;
}
static void WDL_DENORMAL_INLINE denormal_fix_aggressive(double *a)
{
if (((WDL_DENORMAL_DOUBLE_HW(a)+0x100000)&0x7ff00000) < WDL_DENORMAL_DOUBLE_AGGRESSIVE_CUTOFF) *a=0.0;
}
static void WDL_DENORMAL_INLINE denormal_fix(float *a)
{
if (!(WDL_DENORMAL_FLOAT_W(a)&0x7f800000)) *a=0.0f;
}
static void WDL_DENORMAL_INLINE denormal_fix_aggressive(float *a)
{
if (((WDL_DENORMAL_FLOAT_W(a)+0x800000)&0x7f800000) < WDL_DENORMAL_FLOAT_AGGRESSIVE_CUTOFF) *a=0.0f;
}
#endif // cplusplus versions
////////////////////
// this isnt a denormal function but it is similar, so we'll put it here as a bonus
static void WDL_DENORMAL_INLINE GetDoubleMaxAbsValue(double *out, const double *in) // note: the value pointed to by "out" must be >=0.0, __NOT__ <= -0.0
{
unsigned int hw = WDL_DENORMAL_DOUBLE_HW(in)&0x7fffffff;
if (hw >= WDL_DENORMAL_DOUBLE_HW(out) && (hw>WDL_DENORMAL_DOUBLE_HW(out) || WDL_DENORMAL_DOUBLE_LW(in) > WDL_DENORMAL_DOUBLE_LW(out)))
{
WDL_DENORMAL_DOUBLE_LW_NC(out) = WDL_DENORMAL_DOUBLE_LW(in);
WDL_DENORMAL_DOUBLE_HW_NC(out) = hw;
}
}
static void WDL_DENORMAL_INLINE GetFloatMaxAbsValue(float *out, const float *in) // note: the value pointed to by "out" must be >=0.0, __NOT__ <= -0.0
{
unsigned int hw = WDL_DENORMAL_FLOAT_W(in)&0x7fffffff;
if (hw > WDL_DENORMAL_FLOAT_W(out)) WDL_DENORMAL_FLOAT_W_NC(out)=hw;
}
#ifdef __cplusplus
static void WDL_DENORMAL_INLINE GetFloatMaxAbsValue(double *out, const double *in) // note: the value pointed to by "out" must be >=0.0, __NOT__ <= -0.0
{
GetDoubleMaxAbsValue(out,in);
}
#endif
#endif

374
Source/WDL/heapbuf.h Normal file
View File

@ -0,0 +1,374 @@
/*
WDL - heapbuf.h
Copyright (C) 2005 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.
*/
/*
This file provides the interface and implementation for WDL_HeapBuf, a simple
malloc() wrapper for resizeable blocks.
Also in this file is WDL_TypedBuf which is a templated version WDL_HeapBuf
that manages type and type-size.
*/
#ifndef _WDL_HEAPBUF_H_
#define _WDL_HEAPBUF_H_
#ifndef WDL_HEAPBUF_IMPL_ONLY
#ifdef WDL_HEAPBUF_TRACE
#include <windows.h>
#define WDL_HEAPBUF_TRACEPARM(x) ,(x)
#else
#define WDL_HEAPBUF_TRACEPARM(x)
#endif
#include "wdltypes.h"
class WDL_HeapBuf
{
public:
// interface
#ifdef WDL_HEAPBUF_INTF_ONLY
void *Resize(int newsize, bool resizedown=true);
void CopyFrom(const WDL_HeapBuf *hb, bool exactCopyOfConfig=false);
#endif
void *Get() const { return m_size?m_buf:NULL; }
int GetSize() const { return m_size; }
void *GetAligned(int align) const { return (void *)(((UINT_PTR)Get() + (align-1)) & ~(UINT_PTR)(align-1)); }
void SetGranul(int granul) { m_granul = granul; }
int GetGranul() const { return m_granul; }
void *ResizeOK(int newsize, bool resizedown = true) { void *p=Resize(newsize, resizedown); return GetSize() == newsize ? p : NULL; }
WDL_HeapBuf(const WDL_HeapBuf &cp)
{
m_buf=0;
CopyFrom(&cp,true);
}
WDL_HeapBuf &operator=(const WDL_HeapBuf &cp)
{
CopyFrom(&cp,false);
return *this;
}
#ifndef WDL_HEAPBUF_TRACE
explicit WDL_HeapBuf(int granul=4096) : m_buf(NULL), m_alloc(0), m_size(0), m_granul(granul)
{
}
~WDL_HeapBuf()
{
free(m_buf);
}
#else
explicit WDL_HeapBuf(int granul=4096, const char *tracetype="WDL_HeapBuf"
) : m_buf(NULL), m_alloc(0), m_size(0), m_granul(granul)
{
m_tracetype = tracetype;
char tmp[512];
wsprintf(tmp,"WDL_HeapBuf: created type: %s granul=%d\n",tracetype,granul);
OutputDebugString(tmp);
}
~WDL_HeapBuf()
{
char tmp[512];
wsprintf(tmp,"WDL_HeapBuf: destroying type: %s (alloc=%d, size=%d)\n",m_tracetype,m_alloc,m_size);
OutputDebugString(tmp);
free(m_buf);
}
#endif
#endif // !WDL_HEAPBUF_IMPL_ONLY
// implementation bits
#ifndef WDL_HEAPBUF_INTF_ONLY
#ifdef WDL_HEAPBUF_IMPL_ONLY
void *WDL_HeapBuf::Resize(int newsize, bool resizedown)
#else
void *Resize(int newsize, bool resizedown=true)
#endif
{
if (newsize<0) newsize=0;
#ifdef DEBUG_TIGHT_ALLOC // horribly slow, do not use for release builds
if (newsize == m_size) return m_buf;
int a = newsize;
if (a > m_size) a=m_size;
void *newbuf = newsize ? malloc(newsize) : 0;
if (!newbuf && newsize)
{
#ifdef WDL_HEAPBUF_ONMALLOCFAIL
WDL_HEAPBUF_ONMALLOCFAIL(newsize)
#endif
return m_buf;
}
if (newbuf&&m_buf) memcpy(newbuf,m_buf,a);
m_size=m_alloc=newsize;
free(m_buf);
return m_buf=newbuf;
#endif
if (newsize!=m_size || (resizedown && newsize < m_alloc/2))
{
int resizedown_under = 0;
if (resizedown && newsize < m_size)
{
// shrinking buffer: only shrink if allocation decreases to min(alloc/2, alloc-granul*4) or 0
resizedown_under = m_alloc - (m_granul<<2);
if (resizedown_under > m_alloc/2) resizedown_under = m_alloc/2;
if (resizedown_under < 1) resizedown_under=1;
}
if (newsize > m_alloc || newsize < resizedown_under)
{
int granul=newsize/2;
int newalloc;
if (granul < m_granul) granul=m_granul;
if (newsize<1) newalloc=0;
else if (m_granul<4096) newalloc=newsize+granul;
else
{
granul &= ~4095;
if (granul< 4096) granul=4096;
else if (granul>4*1024*1024) granul=4*1024*1024;
newalloc = ((newsize + granul + 96)&~4095)-96;
}
if (newalloc != m_alloc)
{
#ifdef WDL_HEAPBUF_TRACE
char tmp[512];
wsprintf(tmp,"WDL_HeapBuf: type %s realloc(%d) from %d\n",m_tracetype,newalloc,m_alloc);
OutputDebugString(tmp);
#endif
if (newalloc <= 0)
{
free(m_buf);
m_buf=0;
m_alloc=0;
m_size=0;
return 0;
}
void *nbuf=realloc(m_buf,newalloc);
if (!nbuf)
{
if (!(nbuf=malloc(newalloc)))
{
#ifdef WDL_HEAPBUF_ONMALLOCFAIL
WDL_HEAPBUF_ONMALLOCFAIL(newalloc);
#endif
return m_size?m_buf:0; // failed, do not resize
}
if (m_buf)
{
int sz=newsize<m_size?newsize:m_size;
if (sz>0) memcpy(nbuf,m_buf,sz);
free(m_buf);
}
}
m_buf=nbuf;
m_alloc=newalloc;
} // alloc size change
} // need size up or down
m_size=newsize;
} // size change
return m_size?m_buf:0;
}
#ifdef WDL_HEAPBUF_IMPL_ONLY
void WDL_HeapBuf::CopyFrom(const WDL_HeapBuf *hb, bool exactCopyOfConfig)
#else
void CopyFrom(const WDL_HeapBuf *hb, bool exactCopyOfConfig=false)
#endif
{
if (exactCopyOfConfig) // copy all settings
{
free(m_buf);
#ifdef WDL_HEAPBUF_TRACE
m_tracetype = hb->m_tracetype;
#endif
m_granul = hb->m_granul;
m_size=m_alloc=0;
m_buf=hb->m_buf && hb->m_alloc>0 ? malloc(m_alloc = hb->m_alloc) : NULL;
#ifdef WDL_HEAPBUF_ONMALLOCFAIL
if (!m_buf && m_alloc) { WDL_HEAPBUF_ONMALLOCFAIL(m_alloc) } ;
#endif
if (m_buf) memcpy(m_buf,hb->m_buf,m_size = hb->m_size);
else m_alloc=0;
}
else // copy just the data + size
{
const int newsz=hb->GetSize();
Resize(newsz,true);
if (GetSize()!=newsz) Resize(0);
else memcpy(Get(),hb->Get(),newsz);
}
}
#endif // ! WDL_HEAPBUF_INTF_ONLY
#ifndef WDL_HEAPBUF_IMPL_ONLY
private:
void *m_buf;
int m_alloc;
int m_size;
int m_granul;
#if defined(_WIN64) || defined(__LP64__)
public:
int ___pad; // keep size 8 byte aligned
#endif
#ifdef WDL_HEAPBUF_TRACE
const char *m_tracetype;
#endif
};
template<class PTRTYPE> class WDL_TypedBuf
{
public:
PTRTYPE *Get() const { return (PTRTYPE *) m_hb.Get(); }
int GetSize() const { return m_hb.GetSize()/(unsigned int)sizeof(PTRTYPE); }
PTRTYPE *Resize(int newsize, bool resizedown = true) { return (PTRTYPE *)m_hb.Resize(newsize*sizeof(PTRTYPE),resizedown); }
PTRTYPE *ResizeOK(int newsize, bool resizedown = true) { return (PTRTYPE *)m_hb.ResizeOK(newsize*sizeof(PTRTYPE), resizedown); }
PTRTYPE *GetAligned(int align) const { return (PTRTYPE *) m_hb.GetAligned(align); }
PTRTYPE *Add(PTRTYPE val)
{
const int sz=GetSize();
PTRTYPE* p=ResizeOK(sz+1,false);
if (p)
{
p[sz]=val;
return p+sz;
}
return NULL;
}
PTRTYPE *Add(const PTRTYPE *buf, int bufsz)
{
if (bufsz>0)
{
const int sz=GetSize();
PTRTYPE* p=ResizeOK(sz+bufsz,false);
if (p)
{
p+=sz;
if (buf) memcpy(p,buf,bufsz*sizeof(PTRTYPE));
else memset(p,0,bufsz*sizeof(PTRTYPE));
return p;
}
}
return NULL;
}
PTRTYPE *Set(const PTRTYPE *buf, int bufsz)
{
if (bufsz>=0)
{
PTRTYPE* p=ResizeOK(bufsz,false);
if (p)
{
if (buf) memcpy(p,buf,bufsz*sizeof(PTRTYPE));
else memset(p,0,bufsz*sizeof(PTRTYPE));
return p;
}
}
return NULL;
}
PTRTYPE* Insert(PTRTYPE val, int idx)
{
const int sz=GetSize();
if (idx >= 0 && idx <= sz)
{
PTRTYPE* p=ResizeOK(sz+1,false);
if (p)
{
memmove(p+idx+1, p+idx, (sz-idx)*sizeof(PTRTYPE));
p[idx]=val;
return p+idx;
}
}
return NULL;
}
void Delete(int idx)
{
PTRTYPE* p=Get();
const int sz=GetSize();
if (idx >= 0 && idx < sz)
{
memmove(p+idx, p+idx+1, (sz-idx-1)*sizeof(PTRTYPE));
Resize(sz-1,false);
}
}
void SetGranul(int gran) { m_hb.SetGranul(gran); }
int Find(PTRTYPE val) const
{
const PTRTYPE* p=Get();
const int sz=GetSize();
int i;
for (i=0; i < sz; ++i) if (p[i] == val) return i;
return -1;
}
#ifndef WDL_HEAPBUF_TRACE
explicit WDL_TypedBuf(int granul=4096) : m_hb(granul) { }
#else
explicit WDL_TypedBuf(int granul=4096, const char *tracetype="WDL_TypedBuf") : m_hb(granul WDL_HEAPBUF_TRACEPARM(tracetype)) { }
#endif
~WDL_TypedBuf()
{
}
PTRTYPE* begin() const { return static_cast<PTRTYPE*>(m_hb.Get()); }
PTRTYPE* end() const
{
PTRTYPE* temp = static_cast<PTRTYPE*>(m_hb.Get());
return temp + m_hb.GetSize() / sizeof(PTRTYPE);
}
WDL_HeapBuf *GetHeapBuf() { return &m_hb; }
const WDL_HeapBuf *GetHeapBuf() const { return &m_hb; }
private:
WDL_HeapBuf m_hb;
};
#endif // ! WDL_HEAPBUF_IMPL_ONLY
#endif // _WDL_HEAPBUF_H_

639
Source/WDL/resample.cpp Normal file
View File

@ -0,0 +1,639 @@
/*
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()
{
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;
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
memcpy(localin, localin + isrcpos*nch,m_samples_in_rsinbuf*sizeof(WDL_ResampleSample)*nch);
return ret;
}

120
Source/WDL/resample.h Normal file
View File

@ -0,0 +1,120 @@
/*
WDL - resample.h
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.
*/
#ifndef _WDL_RESAMPLE_H_
#define _WDL_RESAMPLE_H_
#include <stdlib.h>
#include <string.h>
#include "wdltypes.h"
#include "heapbuf.h"
// default to floats for sinc filter ceofficients
#ifdef WDL_RESAMPLE_FULL_SINC_PRECISION
typedef double WDL_SincFilterSample;
#else
typedef float WDL_SincFilterSample;
#endif
// default to doubles for audio samples
#ifdef WDL_RESAMPLE_TYPE
typedef WDL_RESAMPLE_TYPE WDL_ResampleSample;
#else
typedef double WDL_ResampleSample;
#endif
#ifndef WDL_RESAMPLE_MAX_FILTERS
#define WDL_RESAMPLE_MAX_FILTERS 4
#endif
#ifndef WDL_RESAMPLE_MAX_NCH
#define WDL_RESAMPLE_MAX_NCH 64
#endif
class WDL_Resampler
{
public:
WDL_Resampler();
~WDL_Resampler();
// if sinc set, it overrides interp or filtercnt
void SetMode(bool interp, int filtercnt, bool sinc, int sinc_size=64, int sinc_interpsize=32);
void SetFilterParms(float filterpos=0.693, float filterq=0.707) { m_filterpos=filterpos; m_filterq=filterq; } // used for filtercnt>0 but not sinc
void SetFeedMode(bool wantInputDriven) { m_feedmode=wantInputDriven; } // if true, that means the first parameter to ResamplePrepare will specify however much input you have, not how much you want
void Reset(double fracpos=0.0);
void SetRates(double rate_in, double rate_out);
double GetCurrentLatency(); // amount of input that has been received but not yet converted to output, in seconds
// req_samples is output samples desired if !wantInputDriven, or if wantInputDriven is input samples that we have
// returns number of samples desired (put these into *inbuffer)
// note that it is safe to call ResamplePrepare without calling ResampleOut (the next call of ResamplePrepare will function as normal)
int ResamplePrepare(int req_samples, int nch, WDL_ResampleSample **inbuffer);
// if numsamples_in < the value return by ResamplePrepare(), then it will be flushed to produce all remaining valid samples
// do NOT call with nsamples_in greater than the value returned from resamplerprpare()! the extra samples will be ignored.
// returns number of samples successfully outputted to out
int ResampleOut(WDL_ResampleSample *out, int nsamples_in, int nsamples_out, int nch);
private:
void BuildLowPass(double filtpos);
void inline SincSample(WDL_ResampleSample *outptr, const WDL_ResampleSample *inptr, double fracpos, int nch, const WDL_SincFilterSample *filter, int filtsz);
void inline SincSample1(WDL_ResampleSample *outptr, const WDL_ResampleSample *inptr, double fracpos, const WDL_SincFilterSample *filter, int filtsz);
void inline SincSample2(WDL_ResampleSample *outptr, const WDL_ResampleSample *inptr, double fracpos, const WDL_SincFilterSample *filter, int filtsz);
double m_sratein WDL_FIXALIGN;
double m_srateout;
double m_fracpos;
double m_ratio;
double m_filter_ratio;
float m_filterq, m_filterpos;
WDL_TypedBuf<WDL_ResampleSample> m_rsinbuf;
WDL_TypedBuf<WDL_SincFilterSample> m_filter_coeffs;
class WDL_Resampler_IIRFilter;
WDL_Resampler_IIRFilter *m_iirfilter;
int m_filter_coeffs_size;
int m_last_requested;
int m_filtlatency;
int m_samples_in_rsinbuf;
int m_lp_oversize;
int m_sincsize;
int m_filtercnt;
int m_sincoversize;
bool m_interp;
bool m_feedmode;
};
#endif

160
Source/WDL/wdltypes.h Normal file
View File

@ -0,0 +1,160 @@
#ifndef _WDLTYPES_
#define _WDLTYPES_
#ifdef _MSC_VER
typedef __int64 WDL_INT64;
typedef unsigned __int64 WDL_UINT64;
#else
typedef long long WDL_INT64;
typedef unsigned long long WDL_UINT64;
#endif
#ifdef _MSC_VER
#define WDL_UINT64_CONST(x) (x##ui64)
#define WDL_INT64_CONST(x) (x##i64)
#else
#define WDL_UINT64_CONST(x) (x##ULL)
#define WDL_INT64_CONST(x) (x##LL)
#endif
#if !defined(_MSC_VER) || _MSC_VER > 1200
#define WDL_DLGRET INT_PTR CALLBACK
#else
#define WDL_DLGRET BOOL CALLBACK
#endif
#ifdef _WIN32
#include <windows.h>
#else
#include <stdint.h>
typedef intptr_t INT_PTR;
typedef uintptr_t UINT_PTR;
#endif
#if defined(__ppc__) || !defined(__cplusplus)
typedef char WDL_bool;
#else
typedef bool WDL_bool;
#endif
#ifndef GWLP_USERDATA
#define GWLP_USERDATA GWL_USERDATA
#define GWLP_WNDPROC GWL_WNDPROC
#define GWLP_HINSTANCE GWL_HINSTANCE
#define GWLP_HWNDPARENT GWL_HWNDPARENT
#define DWLP_USER DWL_USER
#define DWLP_DLGPROC DWL_DLGPROC
#define DWLP_MSGRESULT DWL_MSGRESULT
#define SetWindowLongPtr(a,b,c) SetWindowLong(a,b,c)
#define GetWindowLongPtr(a,b) GetWindowLong(a,b)
#define SetWindowLongPtrW(a,b,c) SetWindowLongW(a,b,c)
#define GetWindowLongPtrW(a,b) GetWindowLongW(a,b)
#define SetWindowLongPtrA(a,b,c) SetWindowLongA(a,b,c)
#define GetWindowLongPtrA(a,b) GetWindowLongA(a,b)
#define GCLP_WNDPROC GCL_WNDPROC
#define GCLP_HICON GCL_HICON
#define GCLP_HICONSM GCL_HICONSM
#define SetClassLongPtr(a,b,c) SetClassLong(a,b,c)
#define GetClassLongPtr(a,b) GetClassLong(a,b)
#endif
#ifdef __GNUC__
// for structures that contain doubles, or doubles in structures that are after stuff of questionable alignment (for OSX/linux)
#define WDL_FIXALIGN __attribute__ ((aligned (8)))
// usage: void func(int a, const char *fmt, ...) WDL_VARARG_WARN(printf,2,3); // note: if member function, this pointer is counted as well, so as member function that would be 3,4
#define WDL_VARARG_WARN(x,n,s) __attribute__ ((format (x,n,s)))
#define WDL_STATICFUNC_UNUSED __attribute__((unused))
#else
#define WDL_FIXALIGN
#define WDL_VARARG_WARN(x,n,s)
#define WDL_STATICFUNC_UNUSED
#endif
#ifndef WDL_WANT_NEW_EXCEPTIONS
#if defined(__cplusplus)
#include <new>
#define WDL_NEW (std::nothrow)
#endif
#else
#define WDL_NEW
#endif
#if !defined(max) && defined(WDL_DEFINE_MINMAX)
#define max(x,y) ((x)<(y)?(y):(x))
#define min(x,y) ((x)<(y)?(x):(y))
#endif
#ifndef wdl_max
#define wdl_max(x,y) ((x)<(y)?(y):(x))
#define wdl_min(x,y) ((x)<(y)?(x):(y))
#define wdl_abs(x) ((x)<0 ? -(x) : (x))
#endif
#ifndef _WIN32
#ifndef strnicmp
#define strnicmp(x,y,z) strncasecmp(x,y,z)
#endif
#ifndef stricmp
#define stricmp(x,y) strcasecmp(x,y)
#endif
#endif
#ifdef WDL_BACKSLASHES_ARE_ORDINARY
#define WDL_IS_DIRCHAR(x) ((x) == '/')
#else
// for multi-platform applications it seems better to treat backslashes as directory separators even if it
// isn't supported by the underying system (for resolving filenames, etc)
#ifdef _WIN32
#define WDL_IS_DIRCHAR(x) ((x) == '\\' || (x) == '/')
#else
#define WDL_IS_DIRCHAR(x) ((x) == '/' || (x) == '\\')
#endif
#endif
#if defined(_WIN32) && !defined(WDL_BACKSLASHES_ARE_ORDINARY)
#define WDL_DIRCHAR '\\'
#define WDL_DIRCHAR_STR "\\"
#else
#define WDL_DIRCHAR '/'
#define WDL_DIRCHAR_STR "/"
#endif
#if defined(_WIN32) || defined(__APPLE__)
// on __APPLE__ we should ideally check the filesystem for case-sensitivity, assuming a case-insensitive-only match
#define wdl_filename_cmp(x,y) stricmp(x,y)
#define wdl_filename_cmpn(x,y,n) strnicmp(x,y,n)
#else
#define wdl_filename_cmp(x,y) strcmp(x,y)
#define wdl_filename_cmpn(x,y,n) strncmp(x,y,n)
#endif
#if defined(__GNUC__) || defined(__INTEL_COMPILER)
#define WDL_likely(x) __builtin_expect(!!(x),1)
#define WDL_unlikely(x) __builtin_expect(!!(x),0)
#else
#define WDL_likely(x) (!!(x))
#define WDL_unlikely(x) (!!(x))
#endif
#if defined(_DEBUG) || defined(DEBUG)
#include <assert.h>
#define WDL_ASSERT(x) assert(x)
#define WDL_NORMALLY(x) (assert(x),1)
#define WDL_NOT_NORMALLY(x) (assert(!(x)),0)
#else
#define WDL_ASSERT(x)
#define WDL_NORMALLY(x) WDL_likely(x)
#define WDL_NOT_NORMALLY(x) WDL_unlikely(x)
#endif
#endif