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 ResInStep = (int) InStep0;
656 const double OutStep0 = DSampleRate / GCD;
657 ResOutStep = (int) OutStep0;
659 if( InStep0 != ResInStep || OutStep0 != ResOutStep )
664 if( ResOutStep > 1500 )
708 const double aDstSampleRate,
const double ReqAtten,
709 const bool IsThird,
const double PrevLatency )
710 : SrcSampleRate( aSrcSampleRate )
711 , DstSampleRate( aDstSampleRate )
713 , FracStep( aSrcSampleRate / aDstSampleRate )
721 InitFracPos = PrevLatency;
722 Latency = (int) InitFracPos;
723 InitFracPos -= Latency;
741 const double spos = InitFracPos * OutStep;
742 InitFracPosW = (int) spos;
743 LatencyFrac = ( spos - InitFracPosW ) / InStep;
745 FilterBank = &CDSPFracDelayFilterBankCache :: getFilterBank(
746 OutStep, 1, 2, ReqAtten, IsThird,
false );
751 FilterBank = &CDSPFracDelayFilterBankCache :: getFilterBank(
752 -1, 3, 8, ReqAtten, IsThird,
true );
757 FilterLen = FilterBank -> getFilterLen();
758 fl2 = FilterLen >> 1;
763 R8BASSERT(( 1 << BufLenBits ) >= FilterLen * 3 );
765 static const CConvolveFn FltConvFn0[ 13 ] = {
766 &CDSPFracInterpolator :: convolve0< 6 >,
767 &CDSPFracInterpolator :: convolve0< 8 >,
768 &CDSPFracInterpolator :: convolve0< 10 >,
769 &CDSPFracInterpolator :: convolve0< 12 >,
770 &CDSPFracInterpolator :: convolve0< 14 >,
771 &CDSPFracInterpolator :: convolve0< 16 >,
772 &CDSPFracInterpolator :: convolve0< 18 >,
773 &CDSPFracInterpolator :: convolve0< 20 >,
774 &CDSPFracInterpolator :: convolve0< 22 >,
775 &CDSPFracInterpolator :: convolve0< 24 >,
776 &CDSPFracInterpolator :: convolve0< 26 >,
777 &CDSPFracInterpolator :: convolve0< 28 >,
778 &CDSPFracInterpolator :: convolve0< 30 >
781 convfn = ( IsWhole ? FltConvFn0[ fl2 - 3 ] :
782 &CDSPFracInterpolator :: convolve2 );
784 R8BCONSOLE(
"CDSPFracInterpolator: src=%.2f dst=%.2f taps=%i "
785 "fracs=%i whole=%i third=%i step=%.6f\n", SrcSampleRate,
786 DstSampleRate, FilterLen, ( IsWhole ? OutStep :
787 FilterBank -> getFilterFracs() ), (
int) IsWhole, (
int) IsThird,
788 aSrcSampleRate / aDstSampleRate );
798 FilterBank -> unref();
804 const int ilat = fl2 + Latency;
808 return( ilat + (
int) (( InitFracPosW +
809 (
double) ReqOutPos * InStep ) / OutStep +
810 LatencyFrac * InStep / OutStep ));
813 return( ilat + (
int) ( InitFracPos + ReqOutPos * SrcSampleRate /
824 return( LatencyFrac );
831 return( (
int) ceil( MaxInLen * DstSampleRate / SrcSampleRate ) + 1 );
836 LatencyLeft = Latency;
842 memset( &Buf[ ReadPos ], 0,
843 (
size_t) ( BufLen - flb ) *
sizeof( Buf[ 0 ]));
847 InPosFracW = InitFracPosW;
851 InPosFrac = InitFracPos;
856 InPosShift = InitFracPos * DstSampleRate / SrcSampleRate;
861 virtual int process(
double* ip,
int l,
double*& op0 )
864 R8BASSERT( ip != op0 || l == 0 || SrcSampleRate > DstSampleRate );
866 if( LatencyLeft != 0 )
868 if( LatencyLeft >= l )
885 const int b =
min( l,
min( BufLen - WritePos, flb - BufLeft ));
887 double*
const wp1 = Buf + WritePos;
888 memcpy( wp1, ip, (
size_t) b *
sizeof( wp1[ 0 ]));
889 const int ec = flo - WritePos;
893 memcpy( wp1 + BufLen, ip,
894 (
size_t)
min( b, ec ) *
sizeof( wp1[ 0 ]));
898 WritePos = ( WritePos + b ) & BufLenMask;
904 op = ( *this.*convfn )( op );
909 if( !IsWhole && InCounter > 1000 )
916 InPosShift = InPosFrac * DstSampleRate / SrcSampleRate;
921 return( (
int) ( op - op0 ));
925 static const int BufLenBits = 8;
933 static const int BufLen = 1 << BufLenBits;
936 static const int BufLenMask = BufLen - 1;
938 double Buf[ BufLen + 29 ];
940 double SrcSampleRate;
941 double DstSampleRate;
991 template<
int fltlen >
992 double* convolve0(
double* op )
995 const int istep = InStep;
996 const int ostep = OutStep;
997 int fpos = InPosFracW;
999 int bl = BufLeft - fl2;
1003 const double*
const ftp = &fb[ fpos ];
1004 const double*
const rp = Buf + rpos;
1007 #if defined( R8B_SSE2 ) && !defined( __INTEL_COMPILER )
1009 __m128d s = _mm_setzero_pd();
1011 for( i = 0; i < fltlen; i += 2 )
1013 const __m128d m = _mm_mul_pd( _mm_load_pd( ftp + i ),
1014 _mm_loadu_pd( rp + i ));
1016 s = _mm_add_pd( s, m );
1019 _mm_storel_pd( op, _mm_add_pd( s, _mm_shuffle_pd( s, s, 1 )));
1021 #elif defined( R8B_NEON )
1023 float64x2_t s = vdupq_n_f64( 0.0 );
1025 for( i = 0; i < fltlen; i += 2 )
1027 s = vmlaq_f64( s, vld1q_f64( ftp + i ), vld1q_f64( rp + i ));
1030 *op = vaddvq_f64( s );
1036 for( i = 0; i < fltlen; i++ )
1038 s += ftp[ i ] * rp[ i ];
1048 const int PosIncr = fpos / ostep;
1049 fpos -= PosIncr * ostep;
1051 rpos = ( rpos + PosIncr ) & BufLenMask;
1069 double* convolve2(
double* op )
1071 const CDSPFracDelayFilterBank& fb = *FilterBank;
1072 const int fltlen = FilterLen;
1073 const double ssr = SrcSampleRate;
1074 const double dsr = DstSampleRate;
1075 double fpos = InPosFrac;
1077 int bl = BufLeft - fl2;
1081 double x = fpos * fb.getFilterFracs();
1082 const int fti = (int) x;
1085 const double x2d = x * x;
1086 const double* ftp = &fb[ fti ];
1087 const double*
const rp = Buf + rpos;
1090 #if defined( R8B_SSE2 ) && defined( R8B_SIMD_ISH )
1092 const __m128d x1 = _mm_set1_pd( x );
1093 const __m128d x2 = _mm_set1_pd( x2d );
1094 __m128d s = _mm_setzero_pd();
1096 for( i = 0; i < fltlen; i += 2 )
1098 const __m128d ftp2 = _mm_load_pd( ftp + 2 );
1099 const __m128d xx1 = _mm_mul_pd( ftp2, x1 );
1100 const __m128d ftp4 = _mm_load_pd( ftp + 4 );
1101 const __m128d xx2 = _mm_mul_pd( ftp4, x2 );
1102 const __m128d ftp0 = _mm_load_pd( ftp );
1105 const __m128d rpi = _mm_loadu_pd( rp + i );
1106 const __m128d xxs = _mm_add_pd( ftp0, _mm_add_pd( xx1, xx2 ));
1108 s = _mm_add_pd( s, _mm_mul_pd( rpi, xxs ));
1111 _mm_storel_pd( op, _mm_add_pd( s, _mm_shuffle_pd( s, s, 1 )));
1113 #elif defined( R8B_NEON ) && defined( R8B_SIMD_ISH )
1115 const float64x2_t x1 = vdupq_n_f64( x );
1116 const float64x2_t x2 = vdupq_n_f64( x2d );
1117 float64x2_t s = vdupq_n_f64( 0.0 );
1119 for( i = 0; i < fltlen; i += 2 )
1121 const float64x2_t ftp2 = vld1q_f64( ftp + 2 );
1122 const float64x2_t xx1 = vmulq_f64( ftp2, x1 );
1123 const float64x2_t ftp4 = vld1q_f64( ftp + 4 );
1124 const float64x2_t xx2 = vmulq_f64( ftp4, x2 );
1125 const float64x2_t ftp0 = vld1q_f64( ftp );
1128 const float64x2_t rpi = vld1q_f64( rp + i );
1129 const float64x2_t xxs = vaddq_f64( ftp0,
1130 vaddq_f64( xx1, xx2 ));
1132 s = vmlaq_f64( s, rpi, xxs );
1135 *op = vaddvq_f64( s );
1141 for( i = 0; i < fltlen; i++ )
1143 s += ( ftp[ 0 ] + ftp[ 1 ] * x + ftp[ 2 ] * x2d ) * rp[ i ];
1156 const int PosIncr = (int) fpos;
1162 const double NextInPos = ( InCounter + InPosShift ) * ssr / dsr;
1163 const int NextInPosInt = (int) NextInPos;
1164 const int PosIncr = NextInPosInt - InPosInt;
1165 InPosInt = NextInPosInt;
1166 fpos = NextInPos - NextInPosInt;
1170 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:655
#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:198
#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:132
#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:103
#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:1079
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:980
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:1014
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:934
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:691
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:707
virtual int process(double *ip, int l, double *&op0)
Performs DSP processing.
Definition CDSPFracInterpolator.h:861
virtual int getLatency() const
Return the latency, in samples, which is present in the output signal.
Definition CDSPFracInterpolator.h:817
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:802
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:827
virtual double getLatencyFrac() const
Returns fractional latency, in samples, which is present in the output signal.
Definition CDSPFracInterpolator.h:822
virtual void clear()
Clears (resets) the state of this object and returns it to the state after construction.
Definition CDSPFracInterpolator.h:834
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:405
Multi-threaded synchronization object class.
Definition r8bbase.h:513