Initial git commit
This commit is contained in:
166
Source/WDL/denormal.h
Normal file
166
Source/WDL/denormal.h
Normal 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
374
Source/WDL/heapbuf.h
Normal 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
639
Source/WDL/resample.cpp
Normal 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
120
Source/WDL/resample.h
Normal 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
160
Source/WDL/wdltypes.h
Normal 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
|
Reference in New Issue
Block a user