16#ifndef R8B_CDSPFRACINTERPOLATOR_INCLUDED
17#define R8B_CDSPFRACINTERPOLATOR_INCLUDED
25 extern int InterpFilterFracs;
42 friend class CDSPFracDelayFilterBankCache;
62 const int aInterpPoints,
const double aReqAtten,
const bool aIsThird )
63 : InitFilterFracs( aFilterFracs )
64 , ElementSize( aElementSize )
65 , InterpPoints( aInterpPoints )
66 , ReqAtten( aReqAtten )
71 R8BASSERT( ElementSize >= 1 && ElementSize <= 4 );
75 const double*
const Params = getWinParams( ReqAtten, IsThird,
78 FilterSize = FilterLen * ElementSize;
80 if( InitFilterFracs == -1 )
82 FilterFracs = (int) ceil( pow( 6.4, ReqAtten / 50.0 ));
86 if( InterpFilterFracs != -1 )
88 FilterFracs = InterpFilterFracs;
95 FilterFracs = InitFilterFracs;
98 Table.alloc( FilterSize * ( FilterFracs + InterpPoints ));
101 sinc.
Len2 = FilterLen / 2;
104 const int pc2 = InterpPoints / 2;
107 for( i = -pc2 + 1; i <= FilterFracs + pc2; i++ )
109 sinc.
FracDelay = (double) ( FilterFracs - i ) / FilterFracs;
110 sinc.
initFrac( CDSPSincFilterGen :: wftKaiser, Params,
true );
111 sinc.
generateFrac( p, &CDSPSincFilterGen :: calcWindowKaiser,
118 const int TablePos2 = FilterSize;
119 const int TablePos3 = FilterSize * 2;
120 const int TablePos4 = FilterSize * 3;
121 const int TablePos5 = FilterSize * 4;
122 const int TablePos6 = FilterSize * 5;
123 const int TablePos7 = FilterSize * 6;
124 const int TablePos8 = FilterSize * 7;
125 double*
const TableEnd = Table + ( FilterFracs + 1 ) * FilterSize;
128 if( InterpPoints == 8 )
130 if( ElementSize == 3 )
135 while( p < TableEnd )
138 p[ TablePos3 ], p[ TablePos4 ], p[ TablePos5 ],
139 p[ TablePos6 ], p[ TablePos7 ], p[ TablePos8 ]);
144 #if defined( R8B_SIMD_ISH )
145 shuffle2_3( Table, TableEnd );
149 if( ElementSize == 4 )
154 while( p < TableEnd )
157 p[ TablePos3 ], p[ TablePos4 ], p[ TablePos5 ],
158 p[ TablePos6 ], p[ TablePos7 ], p[ TablePos8 ]);
163 #if defined( R8B_SIMD_ISH )
164 shuffle2_4( Table, TableEnd );
170 if( ElementSize == 2 )
174 while( p < TableEnd )
176 p[ 1 ] = p[ TablePos2 ] - p[ 0 ];
180 #if defined( R8B_SIMD_ISH )
181 shuffle2_2( Table, TableEnd );
186 R8BCONSOLE(
"CDSPFracDelayFilterBank: fracs=%i order=%i taps=%i "
187 "att=%.1f third=%i\n", FilterFracs, ElementSize - 1, FilterLen,
188 ReqAtten, (
int) IsThird );
207 getWinParams( att, aIsThird, tmp );
226 return( FilterFracs );
239 return( Table[ i * FilterSize ]);
279 static const double* getWinParams(
double& att,
const bool aIsThird,
282 static const int Coeffs2Base = 8;
283 static const int Coeffs2Count = 12;
284 static const double Coeffs2[ Coeffs2Count ][ 3 ] = {
285 { 4.1308468534586913, 1.1752580009977263, 55.5446 },
286 { 4.4241520324148826, 1.8004881791443044, 81.4191 },
287 { 5.2615232289173663, 1.8133318236025469, 96.3392 },
288 { 5.9433751227216174, 1.8730186391986436, 111.1315 },
289 { 6.8308658290513815, 1.8549555110340281, 125.4653 },
290 { 7.6648458290312904, 1.8565766090828464, 139.7379 },
291 { 8.2038728664307605, 1.9269521820570166, 154.0532 },
292 { 8.7865150946655142, 1.9775307667441668, 168.2101 },
293 { 9.5945017884101773, 1.9718456992078597, 182.1076 },
294 { 10.5163141145985240, 1.9504067820201083, 195.5668 },
295 { 10.2382465206362470, 2.1608923446870087, 209.0610 },
296 { 10.9976060250714000, 2.1536533525688935, 222.5010 },
299 static const int Coeffs3Base = 6;
300 static const int Coeffs3Count = 10;
301 static const double Coeffs3[ Coeffs3Count ][ 3 ] = {
302 { 3.9888564562781847, 1.5869927184268915, 66.5701 },
303 { 4.6986694038145007, 1.8086068597928262, 86.4715 },
304 { 5.5995071329337822, 1.8930163360942349, 106.1195 },
305 { 6.3627287800257228, 1.9945748322093975, 125.2307 },
306 { 7.4299550711428308, 1.9893400572347544, 144.3469 },
307 { 8.0667715944075642, 2.0928201458699909, 163.4099 },
308 { 8.7469970226288822, 2.1640279784268355, 181.0694 },
309 { 10.0823430069835230, 2.0896678025321922, 199.2880 },
310 { 10.9222206090489510, 2.1221681162186004, 216.6865 },
311 { 21.2017743894772010, 1.1856768080118900, 233.9188 },
314 const double* Params;
319 while( i != Coeffs3Count - 1 && Coeffs3[ i ][ 2 ] < att )
324 Params = &Coeffs3[ i ][ 0 ];
325 att = Coeffs3[ i ][ 2 ];
326 fltlen = Coeffs3Base + i * 2;
330 while( i != Coeffs2Count - 1 && Coeffs2[ i ][ 2 ] < att )
335 Params = &Coeffs2[ i ][ 0 ];
336 att = Coeffs2[ i ][ 2 ];
337 fltlen = Coeffs2Base + i * 2;
350 static void shuffle2_2(
double* p,
double*
const pe )
354 const double t = p[ 2 ];
369 static void shuffle2_3(
double* p,
double*
const pe )
373 const double t1 = p[ 1 ];
374 const double t2 = p[ 2 ];
375 const double t3 = p[ 3 ];
376 const double t4 = p[ 4 ];
393 static void shuffle2_4(
double* p,
double*
const pe )
397 const double t1 = p[ 1 ];
398 const double t2 = p[ 2 ];
399 const double t3 = p[ 3 ];
400 const double t4 = p[ 4 ];
401 const double t5 = p[ 5 ];
402 const double t6 = p[ 6 ];
425 friend class CDSPFracDelayFilterBank;
445 const int aElementSize,
const int aInterpPoints,
446 double ReqAtten,
const bool IsThird,
const bool IsStatic )
455 CDSPFracDelayFilterBank :: roundReqAtten( ReqAtten, IsThird );
461 CDSPFracDelayFilterBank* PrevObj =
R8B_NULL;
462 CDSPFracDelayFilterBank* CurObj = StaticObjects;
466 if( CurObj -> InitFilterFracs == aFilterFracs &&
467 CurObj -> IsThird == IsThird &&
468 CurObj -> ElementSize == aElementSize &&
469 CurObj -> InterpPoints == aInterpPoints &&
470 CurObj -> ReqAtten == ReqAtten )
476 PrevObj -> Next = CurObj -> Next;
477 CurObj -> Next = StaticObjects.unkeep();
478 StaticObjects = CurObj;
485 CurObj = CurObj -> Next;
490 CurObj =
new CDSPFracDelayFilterBank( aFilterFracs, aElementSize,
491 aInterpPoints, ReqAtten, IsThird );
495 CurObj -> Next = StaticObjects.unkeep();
496 StaticObjects = CurObj;
501 CDSPFracDelayFilterBank* PrevObj =
R8B_NULL;
502 CDSPFracDelayFilterBank* CurObj = Objects;
506 if( CurObj -> InitFilterFracs == aFilterFracs &&
507 CurObj -> IsThird == IsThird &&
508 CurObj -> ElementSize == aElementSize &&
509 CurObj -> InterpPoints == aInterpPoints &&
510 CurObj -> ReqAtten == ReqAtten )
518 if( CurObj -> RefCount == 0 )
532 CurObj -> Next = Objects.unkeep();
541 CurObj = CurObj -> Next;
546 CurObj -> RefCount++;
555 PrevObj -> Next = CurObj -> Next;
561 CurObj =
new CDSPFracDelayFilterBank( aFilterFracs, aElementSize,
562 aInterpPoints, ReqAtten, IsThird );
569 CurObj -> Next = Objects.unkeep();
592inline void CDSPFracDelayFilterBank :: unref()
594 R8BSYNC( CDSPFracDelayFilterBankCache :: getStateSync() );
609inline bool findGCD(
double l,
double s,
double& GCD )
615 const double r = l - s;
645 const double DSampleRate,
int& ResInStep,
int& ResOutStep )
649 if( !
findGCD( SSampleRate, DSampleRate, GCD ))
654 const double InStep0 = SSampleRate / GCD;
655 const double OutStep0 = DSampleRate / GCD;
657 if( OutStep0 > 1500.0 )
665 ResInStep = (int) InStep0;
666 ResOutStep = (int) OutStep0;
670 if( InStep0 != ResInStep || OutStep0 != ResOutStep )
711 const double aDstSampleRate,
const double ReqAtten,
712 const bool IsThird,
const double PrevLatency )
713 : SrcSampleRate( aSrcSampleRate )
714 , DstSampleRate( aDstSampleRate )
716 , FracStep( aSrcSampleRate / aDstSampleRate )
724 InitFracPos = PrevLatency;
725 Latency = (int) InitFracPos;
726 InitFracPos -= Latency;
744 const double spos = InitFracPos * OutStep;
745 InitFracPosW = (int) spos;
746 LatencyFrac = ( spos - InitFracPosW ) / InStep;
748 FilterBank = &CDSPFracDelayFilterBankCache :: getFilterBank(
749 OutStep, 1, 2, ReqAtten, IsThird,
false );
754 FilterBank = &CDSPFracDelayFilterBankCache :: getFilterBank(
755 -1, 3, 8, ReqAtten, IsThird,
true );
760 FilterLen = FilterBank -> getFilterLen();
761 fl2 = FilterLen >> 1;
766 R8BASSERT(( 1 << BufLenBits ) >= FilterLen * 3 );
768 static const CConvolveFn FltConvFn0[ 13 ] = {
769 &CDSPFracInterpolator :: convolve0< 6 >,
770 &CDSPFracInterpolator :: convolve0< 8 >,
771 &CDSPFracInterpolator :: convolve0< 10 >,
772 &CDSPFracInterpolator :: convolve0< 12 >,
773 &CDSPFracInterpolator :: convolve0< 14 >,
774 &CDSPFracInterpolator :: convolve0< 16 >,
775 &CDSPFracInterpolator :: convolve0< 18 >,
776 &CDSPFracInterpolator :: convolve0< 20 >,
777 &CDSPFracInterpolator :: convolve0< 22 >,
778 &CDSPFracInterpolator :: convolve0< 24 >,
779 &CDSPFracInterpolator :: convolve0< 26 >,
780 &CDSPFracInterpolator :: convolve0< 28 >,
781 &CDSPFracInterpolator :: convolve0< 30 >
784 convfn = ( IsWhole ? FltConvFn0[ fl2 - 3 ] :
785 &CDSPFracInterpolator :: convolve2 );
787 R8BCONSOLE(
"CDSPFracInterpolator: src=%.2f dst=%.2f taps=%i "
788 "fracs=%i whole=%i third=%i step=%.6f\n", SrcSampleRate,
789 DstSampleRate, FilterLen, ( IsWhole ? OutStep :
790 FilterBank -> getFilterFracs() ), (
int) IsWhole, (
int) IsThird,
791 aSrcSampleRate / aDstSampleRate );
801 FilterBank -> unref();
807 const int ilat = fl2 + Latency;
811 return( ilat + (
int) (( InitFracPosW +
812 (
double) ReqOutPos * InStep ) / OutStep +
813 LatencyFrac * InStep / OutStep ));
816 return( ilat + (
int) ( InitFracPos + ReqOutPos * SrcSampleRate /
827 return( LatencyFrac );
834 return( (
int) ceil( MaxInLen * DstSampleRate / SrcSampleRate ) + 1 );
839 LatencyLeft = Latency;
845 memset( &Buf[ ReadPos ], 0,
846 (
size_t) ( BufLen - flb ) *
sizeof( Buf[ 0 ]));
850 InPosFracW = InitFracPosW;
854 InPosFrac = InitFracPos;
859 InPosShift = InitFracPos * DstSampleRate / SrcSampleRate;
864 virtual int process(
double* ip,
int l,
double*& op0 )
867 R8BASSERT( ip != op0 || l == 0 || SrcSampleRate > DstSampleRate );
869 if( LatencyLeft != 0 )
871 if( LatencyLeft >= l )
888 const int b =
min( l,
min( BufLen - WritePos, flb - BufLeft ));
890 double*
const wp1 = Buf + WritePos;
891 memcpy( wp1, ip, (
size_t) b *
sizeof( wp1[ 0 ]));
892 const int ec = flo - WritePos;
896 memcpy( wp1 + BufLen, ip,
897 (
size_t)
min( b, ec ) *
sizeof( wp1[ 0 ]));
901 WritePos = ( WritePos + b ) & BufLenMask;
907 op = ( *this.*convfn )( op );
912 if( !IsWhole && InCounter > 1000 )
919 InPosShift = InPosFrac * DstSampleRate / SrcSampleRate;
924 return( (
int) ( op - op0 ));
928 static const int BufLenBits = 8;
936 static const int BufLen = 1 << BufLenBits;
939 static const int BufLenMask = BufLen - 1;
941 double Buf[ BufLen + 29 ];
943 double SrcSampleRate;
944 double DstSampleRate;
994 template<
int fltlen >
995 double* convolve0(
double* op )
998 const int istep = InStep;
999 const int ostep = OutStep;
1000 int fpos = InPosFracW;
1002 int bl = BufLeft - fl2;
1006 const double*
const ftp = &fb[ fpos ];
1007 const double*
const rp = Buf + rpos;
1010 #if defined( R8B_SSE2 ) && !defined( __INTEL_COMPILER )
1012 __m128d s = _mm_setzero_pd();
1014 for( i = 0; i < fltlen; i += 2 )
1016 const __m128d m = _mm_mul_pd( _mm_load_pd( ftp + i ),
1017 _mm_loadu_pd( rp + i ));
1019 s = _mm_add_pd( s, m );
1022 _mm_storel_pd( op, _mm_add_pd( s, _mm_shuffle_pd( s, s, 1 )));
1024 #elif defined( R8B_NEON )
1026 float64x2_t s = vdupq_n_f64( 0.0 );
1028 for( i = 0; i < fltlen; i += 2 )
1030 s = vmlaq_f64( s, vld1q_f64( ftp + i ), vld1q_f64( rp + i ));
1033 *op = vaddvq_f64( s );
1039 for( i = 0; i < fltlen; i++ )
1041 s += ftp[ i ] * rp[ i ];
1051 const int PosIncr = fpos / ostep;
1052 fpos -= PosIncr * ostep;
1054 rpos = ( rpos + PosIncr ) & BufLenMask;
1072 double* convolve2(
double* op )
1074 const CDSPFracDelayFilterBank& fb = *FilterBank;
1075 const int fltlen = FilterLen;
1076 const double ssr = SrcSampleRate;
1077 const double dsr = DstSampleRate;
1078 double fpos = InPosFrac;
1080 int bl = BufLeft - fl2;
1084 double x = fpos * fb.getFilterFracs();
1085 const int fti = (int) x;
1088 const double x2d = x * x;
1089 const double* ftp = &fb[ fti ];
1090 const double*
const rp = Buf + rpos;
1093 #if defined( R8B_SSE2 ) && defined( R8B_SIMD_ISH )
1095 const __m128d x1 = _mm_set1_pd( x );
1096 const __m128d x2 = _mm_set1_pd( x2d );
1097 __m128d s = _mm_setzero_pd();
1099 for( i = 0; i < fltlen; i += 2 )
1101 const __m128d ftp2 = _mm_load_pd( ftp + 2 );
1102 const __m128d xx1 = _mm_mul_pd( ftp2, x1 );
1103 const __m128d ftp4 = _mm_load_pd( ftp + 4 );
1104 const __m128d xx2 = _mm_mul_pd( ftp4, x2 );
1105 const __m128d ftp0 = _mm_load_pd( ftp );
1108 const __m128d rpi = _mm_loadu_pd( rp + i );
1109 const __m128d xxs = _mm_add_pd( ftp0, _mm_add_pd( xx1, xx2 ));
1111 s = _mm_add_pd( s, _mm_mul_pd( rpi, xxs ));
1114 _mm_storel_pd( op, _mm_add_pd( s, _mm_shuffle_pd( s, s, 1 )));
1116 #elif defined( R8B_NEON ) && defined( R8B_SIMD_ISH )
1118 const float64x2_t x1 = vdupq_n_f64( x );
1119 const float64x2_t x2 = vdupq_n_f64( x2d );
1120 float64x2_t s = vdupq_n_f64( 0.0 );
1122 for( i = 0; i < fltlen; i += 2 )
1124 const float64x2_t ftp2 = vld1q_f64( ftp + 2 );
1125 const float64x2_t xx1 = vmulq_f64( ftp2, x1 );
1126 const float64x2_t ftp4 = vld1q_f64( ftp + 4 );
1127 const float64x2_t xx2 = vmulq_f64( ftp4, x2 );
1128 const float64x2_t ftp0 = vld1q_f64( ftp );
1131 const float64x2_t rpi = vld1q_f64( rp + i );
1132 const float64x2_t xxs = vaddq_f64( ftp0,
1133 vaddq_f64( xx1, xx2 ));
1135 s = vmlaq_f64( s, rpi, xxs );
1138 *op = vaddvq_f64( s );
1144 for( i = 0; i < fltlen; i++ )
1146 s += ( ftp[ 0 ] + ftp[ 1 ] * x + ftp[ 2 ] * x2d ) * rp[ i ];
1159 const int PosIncr = (int) fpos;
1165 const double NextInPos = ( InCounter + InPosShift ) * ssr / dsr;
1166 const int NextInPosInt = (int) NextInPos;
1167 const int PosIncr = NextInPosInt - InPosInt;
1168 InPosInt = NextInPosInt;
1169 fpos = NextInPos - NextInPosInt;
1173 rpos = ( rpos + PosIncr ) & BufLenMask;
The base virtual class for DSP processing algorithms.
Sinc function-based FIR filter generator class.
#define R8BSYNC(SyncObject)
Thread synchronization macro.
Definition r8bbase.h:668
#define R8B_EXITDTOR
Macro that defines the attribute specifying that the exit-time destructor should be called for a stat...
Definition r8bbase.h:149
#define R8B_NULL
The "null pointer" value, portable between C++11 and earlier C++ versions.
Definition r8bbase.h:101
#define R8BNOCTOR(ClassName)
Macro that defines empty copy-constructor and copy operator with the "private:" prefix.
Definition r8bbase.h:209
#define R8BASSERT(e)
Assertion macro used to check for certain run-time conditions. By default, no action is taken if asse...
Definition r8bconf.h:28
#define R8B_FASTTIMING
This macro, when equal to 1, enables a fast interpolation sample timing technique.
Definition r8bconf.h:140
#define R8B_BASECLASS
Macro defines the name of the class from which all classes that are designed to be created on heap ar...
Definition r8bconf.h:56
#define R8B_FRACBANK_CACHE_MAX
Macro specifies the number of whole-number stepping fractional delay filter banks kept in the cache a...
Definition r8bconf.h:107
#define R8BCONSOLE(...)
Console output macro, used to output various resampler status strings, including filter design parame...
Definition r8bconf.h:41
The "r8brain-free-src" library namespace.
Definition CDSPBlockConvolver.h:22
bool getWholeStepping(const double SSampleRate, const double DSampleRate, int &ResInStep, int &ResOutStep)
Evaluates source and destination sample rate ratio and returns the required input and output stepping...
Definition CDSPFracInterpolator.h:644
T min(const T &v1, const T &v2)
Returns minimum of two values.
Definition r8bbase.h:1092
void calcSpline3p8Coeffs(double *const c, const double xm3, const double xm2, const double xm1, const double x0, const double x1, const double x2, const double x3, const double x4)
Calculates 3rd order spline coefficients, using 8 points.
Definition r8bbase.h:993
void calcSpline2p8Coeffs(double *const c, const double xm3, const double xm2, const double xm1, const double x0, const double x1, const double x2, const double x3, const double x4)
Calculates 2nd order spline coefficients, using 8 points.
Definition r8bbase.h:1027
bool findGCD(double l, double s, double &GCD)
Interatively searches for a greatest common denominator (GCD) of 2 numbers.
Definition CDSPFracInterpolator.h:609
void normalizeFIRFilter(double *const p, const int l, const double DCGain, const int pstep=1)
FIR filter's gain normalization.
Definition r8bbase.h:947
Sinc function-based fractional delay filter bank class.
Definition CDSPFracInterpolator.h:39
void unref()
Reduces reference count to this object.
Definition CDSPFracInterpolator.h:592
int getFilterFracs() const
Returns the number of fractional positions sampled by the bank.
Definition CDSPFracInterpolator.h:224
const double & operator[](const int i) const
Returns reference to the filter.
Definition CDSPFracInterpolator.h:235
static void roundReqAtten(double &att, const bool aIsThird)
Rounds the specified attenuation to the nearest effective value.
Definition CDSPFracInterpolator.h:204
int getFilterLen() const
Returns the length of the filter, in samples (taps). Always an even number, not less than 6.
Definition CDSPFracInterpolator.h:215
CDSPFracDelayFilterBank(const int aFilterFracs, const int aElementSize, const int aInterpPoints, const double aReqAtten, const bool aIsThird)
Initializes the filter bank object.
Definition CDSPFracInterpolator.h:61
Fractional delay filter cache class.
Definition CDSPFracInterpolator.h:422
static CDSPFracDelayFilterBank & getFilterBank(const int aFilterFracs, const int aElementSize, const int aInterpPoints, double ReqAtten, const bool IsThird, const bool IsStatic)
Calculates or returns reference to a previously calculated (cached) fractional delay filter bank.
Definition CDSPFracInterpolator.h:444
static CSyncObject & getStateSync()
Returns reference to global filter bank cache sync object.
Definition CDSPFracInterpolator.h:580
Fractional delay filter bank-based interpolator class.
Definition CDSPFracInterpolator.h:694
CDSPFracInterpolator(const double aSrcSampleRate, const double aDstSampleRate, const double ReqAtten, const bool IsThird, const double PrevLatency)
Initalizes the interpolator. It is important to call the getMaxOutLen() function afterwards to obtain...
Definition CDSPFracInterpolator.h:710
virtual int process(double *ip, int l, double *&op0)
Performs DSP processing.
Definition CDSPFracInterpolator.h:864
virtual int getLatency() const
Return the latency, in samples, which is present in the output signal.
Definition CDSPFracInterpolator.h:820
virtual int getInLenBeforeOutPos(const int ReqOutPos) const
Returns the number of input samples required to advance to the specified output sample position (so t...
Definition CDSPFracInterpolator.h:805
virtual int getMaxOutLen(const int MaxInLen) const
Returns the maximal length of the output buffer required when processing the MaxInLen number of input...
Definition CDSPFracInterpolator.h:830
virtual double getLatencyFrac() const
Returns fractional latency, in samples, which is present in the output signal.
Definition CDSPFracInterpolator.h:825
virtual void clear()
Clears (resets) the state of this object and returns it to the state after construction.
Definition CDSPFracInterpolator.h:837
Sinc function-based FIR filter generator class.
Definition CDSPSincFilterGen.h:33
double FracDelay
Fractional delay in the range [0; 1], used only in the generateFrac() function. Note that the FracDel...
Definition CDSPSincFilterGen.h:52
void generateFrac(double *op, CWindowFunc wfunc=&CDSPSincFilterGen ::calcWindowBlackman, const int opinc=1)
Calculates windowed fractional delay filter kernel.
Definition CDSPSincFilterGen.h:452
void initFrac(const EWindowFunctionType WinType=wftCosine, const double *const Params=R8B_NULL, const bool UsePower=false)
Initializes this structure for generation of full-bandwidth fractional delay sinc filter kernel.
Definition CDSPSincFilterGen.h:168
double Len2
Required half filter kernel's length in samples (can be a fractional value). Final physical kernel le...
Definition CDSPSincFilterGen.h:35
Pointer-to-object "keeper" class with automatic deletion.
Definition r8bbase.h:418
Multi-threaded synchronization object class.
Definition r8bbase.h:526