15#ifndef R8B_CDSPFRACINTERPOLATOR_INCLUDED
16#define R8B_CDSPFRACINTERPOLATOR_INCLUDED
24 extern int InterpFilterFracs;
61 const int aInterpPoints,
const double aReqAtten,
const bool aIsThird )
62 : InitFilterFracs( aFilterFracs )
63 , ElementSize( aElementSize )
64 , InterpPoints( aInterpPoints )
65 , ReqAtten( aReqAtten )
70 R8BASSERT( ElementSize >= 1 && ElementSize <= 4 );
74 const double*
const Params = getWinParams( ReqAtten, IsThird,
77 FilterSize = FilterLen * ElementSize;
79 if( InitFilterFracs == -1 )
81 FilterFracs = (int) ceil( pow( 6.4, ReqAtten / 50.0 ));
85 if( InterpFilterFracs != -1 )
87 FilterFracs = InterpFilterFracs;
94 FilterFracs = InitFilterFracs;
97 Table.
alloc( FilterSize * ( FilterFracs + InterpPoints ));
100 sinc.
Len2 = FilterLen / 2;
103 const int pc2 = InterpPoints / 2;
106 for( i = -pc2 + 1; i <= FilterFracs + pc2; i++ )
108 sinc.
FracDelay = (double) ( FilterFracs - i ) / FilterFracs;
109 sinc.
initFrac( CDSPSincFilterGen :: wftKaiser, Params,
true );
110 sinc.
generateFrac( p, &CDSPSincFilterGen :: calcWindowKaiser,
117 const int TablePos2 = FilterSize;
118 const int TablePos3 = FilterSize * 2;
119 const int TablePos4 = FilterSize * 3;
120 const int TablePos5 = FilterSize * 4;
121 const int TablePos6 = FilterSize * 5;
122 const int TablePos7 = FilterSize * 6;
123 const int TablePos8 = FilterSize * 7;
124 double*
const TableEnd = Table + ( FilterFracs + 1 ) * FilterSize;
127 if( InterpPoints == 8 )
129 if( ElementSize == 3 )
134 while( p < TableEnd )
137 p[ TablePos3 ], p[ TablePos4 ], p[ TablePos5 ],
138 p[ TablePos6 ], p[ TablePos7 ], p[ TablePos8 ]);
143 #if defined( R8B_SIMD_ISH )
144 shuffle2_3( Table, TableEnd );
148 if( ElementSize == 4 )
153 while( p < TableEnd )
156 p[ TablePos3 ], p[ TablePos4 ], p[ TablePos5 ],
157 p[ TablePos6 ], p[ TablePos7 ], p[ TablePos8 ]);
162 #if defined( R8B_SIMD_ISH )
163 shuffle2_4( Table, TableEnd );
169 if( ElementSize == 2 )
173 while( p < TableEnd )
175 p[ 1 ] = p[ TablePos2 ] - p[ 0 ];
179 #if defined( R8B_SIMD_ISH )
180 shuffle2_2( Table, TableEnd );
185 R8BCONSOLE(
"CDSPFracDelayFilterBank: fracs=%i order=%i taps=%i "
186 "att=%.1f third=%i\n", FilterFracs, ElementSize - 1, FilterLen,
187 ReqAtten, (
int) IsThird );
207 getWinParams( att, aIsThird, tmp );
226 return( FilterFracs );
238 return( Table[ i * FilterSize ]);
276 static const double* getWinParams(
double& att,
const bool aIsThird,
279 static const int Coeffs2Base = 8;
280 static const int Coeffs2Count = 12;
281 static const double Coeffs2[ Coeffs2Count ][ 3 ] = {
282 { 4.1308468534586913, 1.1752580009977263, 55.5446 },
283 { 4.4241520324148826, 1.8004881791443044, 81.4191 },
284 { 5.2615232289173663, 1.8133318236025469, 96.3392 },
285 { 5.9433751227216174, 1.8730186391986436, 111.1315 },
286 { 6.8308658290513815, 1.8549555110340281, 125.4653 },
287 { 7.6648458290312904, 1.8565766090828464, 139.7379 },
288 { 8.2038728664307605, 1.9269521820570166, 154.0532 },
289 { 8.7865150946655142, 1.9775307667441668, 168.2101 },
290 { 9.5945017884101773, 1.9718456992078597, 182.1076 },
291 { 10.5163141145985240, 1.9504067820201083, 195.5668 },
292 { 10.2382465206362470, 2.1608923446870087, 209.0610 },
293 { 10.9976060250714000, 2.1536533525688935, 222.5010 },
296 static const int Coeffs3Base = 6;
297 static const int Coeffs3Count = 10;
298 static const double Coeffs3[ Coeffs3Count ][ 3 ] = {
299 { 3.9888564562781847, 1.5869927184268915, 66.5701 },
300 { 4.6986694038145007, 1.8086068597928262, 86.4715 },
301 { 5.5995071329337822, 1.8930163360942349, 106.1195 },
302 { 6.3627287800257228, 1.9945748322093975, 125.2307 },
303 { 7.4299550711428308, 1.9893400572347544, 144.3469 },
304 { 8.0667715944075642, 2.0928201458699909, 163.4099 },
305 { 8.7469970226288822, 2.1640279784268355, 181.0694 },
306 { 10.0823430069835230, 2.0896678025321922, 199.2880 },
307 { 10.9222206090489510, 2.1221681162186004, 216.6865 },
308 { 21.2017743894772010, 1.1856768080118900, 233.9188 },
311 const double* Params;
316 while( i != Coeffs3Count - 1 && Coeffs3[ i ][ 2 ] < att )
321 Params = &Coeffs3[ i ][ 0 ];
322 att = Coeffs3[ i ][ 2 ];
323 fltlen = Coeffs3Base + i * 2;
327 while( i != Coeffs2Count - 1 && Coeffs2[ i ][ 2 ] < att )
332 Params = &Coeffs2[ i ][ 0 ];
333 att = Coeffs2[ i ][ 2 ];
334 fltlen = Coeffs2Base + i * 2;
347 static void shuffle2_2(
double* p,
double*
const pe )
351 const double t = p[ 2 ];
366 static void shuffle2_3(
double* p,
double*
const pe )
370 const double t1 = p[ 1 ];
371 const double t2 = p[ 2 ];
372 const double t3 = p[ 3 ];
373 const double t4 = p[ 4 ];
390 static void shuffle2_4(
double* p,
double*
const pe )
394 const double t1 = p[ 1 ];
395 const double t2 = p[ 2 ];
396 const double t3 = p[ 3 ];
397 const double t4 = p[ 4 ];
398 const double t5 = p[ 5 ];
399 const double t6 = p[ 6 ];
454 const int aElementSize,
const int aInterpPoints,
455 double ReqAtten,
const bool IsThird,
const bool IsStatic )
457 CDSPFracDelayFilterBank :: roundReqAtten( ReqAtten, IsThird );
466 while( CurObj != NULL )
468 if( CurObj -> InitFilterFracs == aFilterFracs &&
469 CurObj -> IsThird == IsThird &&
470 CurObj -> ElementSize == aElementSize &&
471 CurObj -> InterpPoints == aInterpPoints &&
472 CurObj -> ReqAtten == ReqAtten )
474 if( PrevObj != NULL )
478 PrevObj -> Next = CurObj -> Next;
479 CurObj -> Next = StaticObjects.unkeep();
480 StaticObjects = CurObj;
487 CurObj = CurObj -> Next;
493 aInterpPoints, ReqAtten, IsThird );
497 CurObj -> Next = StaticObjects.unkeep();
498 StaticObjects = CurObj;
506 while( CurObj != NULL )
508 if( CurObj -> InitFilterFracs == aFilterFracs &&
509 CurObj -> IsThird == IsThird &&
510 CurObj -> ElementSize == aElementSize &&
511 CurObj -> InterpPoints == aInterpPoints &&
512 CurObj -> ReqAtten == ReqAtten )
519 if( CurObj -> RefCount == 0 )
523 PrevObj -> Next = NULL;
532 PrevObj -> Next = NULL;
533 CurObj -> Next = Objects.unkeep();
542 CurObj = CurObj -> Next;
547 CurObj -> RefCount++;
549 if( PrevObj == NULL )
556 PrevObj -> Next = CurObj -> Next;
563 aInterpPoints, ReqAtten, IsThird );
570 CurObj -> Next = Objects.unkeep();
590inline void CDSPFracDelayFilterBank :: unref()
592 R8BSYNC( CDSPFracDelayFilterBankCache :: StateSync );
608inline bool findGCD(
double l,
double s,
double& GCD )
614 const double r = l - s;
643 const double DSampleRate,
int& ResInStep,
int& ResOutStep )
647 if( !
findGCD( SSampleRate, DSampleRate, GCD ))
652 const double InStep0 = SSampleRate / GCD;
653 ResInStep = (int) InStep0;
654 const double OutStep0 = DSampleRate / GCD;
655 ResOutStep = (int) OutStep0;
657 if( InStep0 != ResInStep || OutStep0 != ResOutStep )
662 if( ResOutStep > 1500 )
706 const double aDstSampleRate,
const double ReqAtten,
707 const bool IsThird,
const double PrevLatency )
708 : SrcSampleRate( aSrcSampleRate )
709 , DstSampleRate( aDstSampleRate )
711 , FracStep( aSrcSampleRate / aDstSampleRate )
719 InitFracPos = PrevLatency;
720 Latency = (int) InitFracPos;
721 InitFracPos -= Latency;
739 const double spos = InitFracPos * OutStep;
740 InitFracPosW = (int) spos;
741 LatencyFrac = ( spos - InitFracPosW ) / InStep;
743 FilterBank = &CDSPFracDelayFilterBankCache :: getFilterBank(
744 OutStep, 1, 2, ReqAtten, IsThird,
false );
749 FilterBank = &CDSPFracDelayFilterBankCache :: getFilterBank(
750 -1, 3, 8, ReqAtten, IsThird,
true );
755 FilterLen = FilterBank -> getFilterLen();
756 fl2 = FilterLen >> 1;
761 R8BASSERT(( 1 << BufLenBits ) >= FilterLen * 3 );
763 static const CConvolveFn FltConvFn0[ 13 ] = {
764 &CDSPFracInterpolator :: convolve0< 6 >,
765 &CDSPFracInterpolator :: convolve0< 8 >,
766 &CDSPFracInterpolator :: convolve0< 10 >,
767 &CDSPFracInterpolator :: convolve0< 12 >,
768 &CDSPFracInterpolator :: convolve0< 14 >,
769 &CDSPFracInterpolator :: convolve0< 16 >,
770 &CDSPFracInterpolator :: convolve0< 18 >,
771 &CDSPFracInterpolator :: convolve0< 20 >,
772 &CDSPFracInterpolator :: convolve0< 22 >,
773 &CDSPFracInterpolator :: convolve0< 24 >,
774 &CDSPFracInterpolator :: convolve0< 26 >,
775 &CDSPFracInterpolator :: convolve0< 28 >,
776 &CDSPFracInterpolator :: convolve0< 30 >
779 convfn = ( IsWhole ? FltConvFn0[ fl2 - 3 ] :
780 &CDSPFracInterpolator :: convolve2 );
782 R8BCONSOLE(
"CDSPFracInterpolator: src=%.2f dst=%.2f taps=%i "
783 "fracs=%i whole=%i third=%i step=%.6f\n", SrcSampleRate,
784 DstSampleRate, FilterLen, ( IsWhole ? OutStep :
785 FilterBank -> getFilterFracs() ), (
int) IsWhole, (
int) IsThird,
786 aSrcSampleRate / aDstSampleRate );
796 FilterBank -> unref();
802 const int ilat = fl2 + Latency;
806 return( ilat + (
int) (( InitFracPosW +
807 (
double) ReqOutPos * InStep ) / OutStep +
808 LatencyFrac * InStep / OutStep ));
811 return( ilat + (
int) ( InitFracPos + ReqOutPos * SrcSampleRate /
822 return( LatencyFrac );
829 return( (
int) ceil( MaxInLen * DstSampleRate / SrcSampleRate ) + 1 );
834 LatencyLeft = Latency;
840 memset( &Buf[ ReadPos ], 0, ( BufLen - flb ) *
sizeof( Buf[ 0 ]));
844 InPosFracW = InitFracPosW;
848 InPosFrac = InitFracPos;
853 InPosShift = InitFracPos * DstSampleRate / SrcSampleRate;
858 virtual int process(
double* ip,
int l,
double*& op0 )
861 R8BASSERT( ip != op0 || l == 0 || SrcSampleRate > DstSampleRate );
863 if( LatencyLeft != 0 )
865 if( LatencyLeft >= l )
882 const int b =
min( l,
min( BufLen - WritePos, flb - BufLeft ));
884 double*
const wp1 = Buf + WritePos;
885 memcpy( wp1, ip, b *
sizeof( wp1[ 0 ]));
886 const int ec = flo - WritePos;
890 memcpy( wp1 + BufLen, ip,
min( b, ec ) *
sizeof( wp1[ 0 ]));
894 WritePos = ( WritePos + b ) & BufLenMask;
900 op = ( *this.*convfn )( op );
905 if( !IsWhole && InCounter > 1000 )
912 InPosShift = InPosFrac * DstSampleRate / SrcSampleRate;
917 return( (
int) ( op - op0 ));
921 static const int BufLenBits = 8;
929 static const int BufLen = 1 << BufLenBits;
932 static const int BufLenMask = BufLen - 1;
934 double Buf[ BufLen + 29 ];
936 double SrcSampleRate;
937 double DstSampleRate;
987 template<
int fltlen >
988 double* convolve0(
double* op )
991 const int istep = InStep;
992 const int ostep = OutStep;
993 int fpos = InPosFracW;
995 int bl = BufLeft - fl2;
999 const double*
const ftp = &fb[ fpos ];
1000 const double*
const rp = Buf + rpos;
1003 #if defined( R8B_SSE2 ) && !defined( __INTEL_COMPILER )
1005 __m128d s = _mm_setzero_pd();
1007 for( i = 0; i < fltlen; i += 2 )
1009 const __m128d m = _mm_mul_pd( _mm_load_pd( ftp + i ),
1010 _mm_loadu_pd( rp + i ));
1012 s = _mm_add_pd( s, m );
1015 _mm_storel_pd( op, _mm_add_pd( s, _mm_shuffle_pd( s, s, 1 )));
1017 #elif defined( R8B_NEON )
1019 float64x2_t s = vdupq_n_f64( 0.0 );
1021 for( i = 0; i < fltlen; i += 2 )
1023 s = vmlaq_f64( s, vld1q_f64( ftp + i ), vld1q_f64( rp + i ));
1026 *op = vaddvq_f64( s );
1032 for( i = 0; i < fltlen; i++ )
1034 s += ftp[ i ] * rp[ i ];
1044 const int PosIncr = fpos / ostep;
1045 fpos -= PosIncr * ostep;
1047 rpos = ( rpos + PosIncr ) & BufLenMask;
1065 double* convolve2(
double* op )
1067 const CDSPFracDelayFilterBank& fb = *FilterBank;
1068 const int fltlen = FilterLen;
1069 const double ssr = SrcSampleRate;
1070 const double dsr = DstSampleRate;
1071 double fpos = InPosFrac;
1073 int bl = BufLeft - fl2;
1078 const int fti = (int) x;
1081 const double x2d = x * x;
1082 const double* ftp = &fb[ fti ];
1083 const double*
const rp = Buf + rpos;
1086 #if defined( R8B_SSE2 ) && defined( R8B_SIMD_ISH )
1088 const __m128d x1 = _mm_set1_pd( x );
1089 const __m128d x2 = _mm_set1_pd( x2d );
1090 __m128d s = _mm_setzero_pd();
1092 for( i = 0; i < fltlen; i += 2 )
1094 const __m128d ftp2 = _mm_load_pd( ftp + 2 );
1095 const __m128d xx1 = _mm_mul_pd( ftp2, x1 );
1096 const __m128d ftp4 = _mm_load_pd( ftp + 4 );
1097 const __m128d xx2 = _mm_mul_pd( ftp4, x2 );
1098 const __m128d ftp0 = _mm_load_pd( ftp );
1101 const __m128d rpi = _mm_loadu_pd( rp + i );
1102 const __m128d xxs = _mm_add_pd( ftp0, _mm_add_pd( xx1, xx2 ));
1104 s = _mm_add_pd( s, _mm_mul_pd( rpi, xxs ));
1107 _mm_storel_pd( op, _mm_add_pd( s, _mm_shuffle_pd( s, s, 1 )));
1109 #elif defined( R8B_NEON ) && defined( R8B_SIMD_ISH )
1111 const float64x2_t x1 = vdupq_n_f64( x );
1112 const float64x2_t x2 = vdupq_n_f64( x2d );
1113 float64x2_t s = vdupq_n_f64( 0.0 );
1115 for( i = 0; i < fltlen; i += 2 )
1117 const float64x2_t ftp2 = vld1q_f64( ftp + 2 );
1118 const float64x2_t xx1 = vmulq_f64( ftp2, x1 );
1119 const float64x2_t ftp4 = vld1q_f64( ftp + 4 );
1120 const float64x2_t xx2 = vmulq_f64( ftp4, x2 );
1121 const float64x2_t ftp0 = vld1q_f64( ftp );
1124 const float64x2_t rpi = vld1q_f64( rp + i );
1125 const float64x2_t xxs = vaddq_f64( ftp0,
1126 vaddq_f64( xx1, xx2 ));
1128 s = vmlaq_f64( s, rpi, xxs );
1131 *op = vaddvq_f64( s );
1137 for( i = 0; i < fltlen; i++ )
1139 s += ( ftp[ 0 ] + ftp[ 1 ] * x + ftp[ 2 ] * x2d ) * rp[ i ];
1152 const int PosIncr = (int) fpos;
1158 const double NextInPos = ( InCounter + InPosShift ) * ssr / dsr;
1159 const int NextInPosInt = (int) NextInPos;
1160 const int PosIncr = NextInPosInt - InPosInt;
1161 InPosInt = NextInPosInt;
1162 fpos = NextInPos - NextInPosInt;
1166 rpos = ( rpos + PosIncr ) & BufLenMask;
The base virtual class for DSP processing algorithms.
Sinc function-based FIR filter generator class.
#define R8BSYNC(SyncObject)
Definition: r8bbase.h:660
#define R8BNOCTOR(ClassName)
Definition: r8bbase.h:154
#define R8BASSERT(e)
Definition: r8bconf.h:27
#define R8B_FASTTIMING
Definition: r8bconf.h:121
#define R8B_BASECLASS
Definition: r8bconf.h:54
#define R8B_FRACBANK_CACHE_MAX
Definition: r8bconf.h:96
#define R8BCONSOLE(...)
Definition: r8bconf.h:40
The "r8brain-free-src" library namespace.
Definition: CDSPBlockConvolver.h:21
bool getWholeStepping(const double SSampleRate, const double DSampleRate, int &ResInStep, int &ResOutStep)
Definition: CDSPFracInterpolator.h:642
T min(const T &v1, const T &v2)
Definition: r8bbase.h:1063
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)
Definition: r8bbase.h:972
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)
Definition: r8bbase.h:1004
bool findGCD(double l, double s, double &GCD)
Definition: CDSPFracInterpolator.h:608
void normalizeFIRFilter(double *const p, const int l, const double DCGain, const int pstep=1)
Definition: r8bbase.h:928
Sinc function-based fractional delay filter bank class.
Definition: CDSPFracInterpolator.h:38
void unref()
Definition: CDSPFracInterpolator.h:590
int getFilterFracs() const
Definition: CDSPFracInterpolator.h:224
const double & operator[](const int i) const
Definition: CDSPFracInterpolator.h:234
static void roundReqAtten(double &att, const bool aIsThird)
Definition: CDSPFracInterpolator.h:204
int getFilterLen() const
Definition: CDSPFracInterpolator.h:215
CDSPFracDelayFilterBank(const int aFilterFracs, const int aElementSize, const int aInterpPoints, const double aReqAtten, const bool aIsThird)
Definition: CDSPFracInterpolator.h:60
Fractional delay filter cache class.
Definition: CDSPFracInterpolator.h:419
static CDSPFracDelayFilterBank & getFilterBank(const int aFilterFracs, const int aElementSize, const int aInterpPoints, double ReqAtten, const bool IsThird, const bool IsStatic)
Definition: CDSPFracInterpolator.h:453
static int getObjCount()
Definition: CDSPFracInterpolator.h:430
Fractional delay filter bank-based interpolator class.
Definition: CDSPFracInterpolator.h:689
CDSPFracInterpolator(const double aSrcSampleRate, const double aDstSampleRate, const double ReqAtten, const bool IsThird, const double PrevLatency)
Definition: CDSPFracInterpolator.h:705
virtual int process(double *ip, int l, double *&op0)
Definition: CDSPFracInterpolator.h:858
virtual int getLatency() const
Definition: CDSPFracInterpolator.h:815
virtual int getInLenBeforeOutPos(const int ReqOutPos) const
Definition: CDSPFracInterpolator.h:800
virtual int getMaxOutLen(const int MaxInLen) const
Definition: CDSPFracInterpolator.h:825
virtual double getLatencyFrac() const
Definition: CDSPFracInterpolator.h:820
virtual void clear()
Definition: CDSPFracInterpolator.h:832
The base virtual class for DSP processing algorithms.
Definition: CDSPProcessor.h:32
Sinc function-based FIR filter generator class.
Definition: CDSPSincFilterGen.h:32
double FracDelay
Fractional delay in the range [0; 1], used only in the generateFrac() function. Note that the FracDel...
Definition: CDSPSincFilterGen.h:60
void initFrac(const EWindowFunctionType WinType=wftCosine, const double *const Params=NULL, const bool UsePower=false)
Definition: CDSPSincFilterGen.h:175
void generateFrac(double *op, CWindowFunc wfunc=&CDSPSincFilterGen ::calcWindowBlackman, const int opinc=1)
Definition: CDSPSincFilterGen.h:459
double Len2
Required half filter kernel's length in samples (can be a fractional value). Final physical kernel le...
Definition: CDSPSincFilterGen.h:34
void alloc(const int Capacity)
Definition: r8bbase.h:343
Pointer-to-object "keeper" class with automatic deletion.
Definition: r8bbase.h:428
Multi-threaded synchronization object class.
Definition: r8bbase.h:526