16#ifndef R8B_CDSPFRACINTERPOLATOR_INCLUDED
17#define R8B_CDSPFRACINTERPOLATOR_INCLUDED
25 extern int InterpFilterFracs;
39 private CSinglyLinkedListItem< CDSPFracDelayFilterBank >
44 friend class CDSPFracDelayFilterBankCache;
64 const int aInterpPoints,
const double aReqAtten,
const bool aIsThird )
65 : InitFilterFracs( aFilterFracs )
66 , ElementSize( aElementSize )
67 , InterpPoints( aInterpPoints )
68 , ReqAtten( aReqAtten )
72 R8BASSERT( ElementSize >= 1 && ElementSize <= 4 );
76 const double*
const Params = getWinParams( ReqAtten, IsThird,
79 FilterSize = FilterLen * ElementSize;
81 if( InitFilterFracs == -1 )
83 FilterFracs = (int) ceil( pow( 6.4, ReqAtten / 50.0 ));
87 if( InterpFilterFracs != -1 )
89 FilterFracs = InterpFilterFracs;
96 FilterFracs = InitFilterFracs;
99 Table.alloc( FilterSize * ( FilterFracs + InterpPoints ));
102 sinc.
Len2 = FilterLen / 2;
105 const int pc2 = InterpPoints / 2;
108 for( i = -pc2 + 1; i <= FilterFracs + pc2; i++ )
110 sinc.
FracDelay = (double) ( FilterFracs - i ) / FilterFracs;
111 sinc.
initFrac( CDSPSincFilterGen :: wftKaiser, Params,
true );
112 sinc.
generateFrac( p, &CDSPSincFilterGen :: calcWindowKaiser,
119 const int TablePos2 = FilterSize;
120 const int TablePos3 = FilterSize * 2;
121 const int TablePos4 = FilterSize * 3;
122 const int TablePos5 = FilterSize * 4;
123 const int TablePos6 = FilterSize * 5;
124 const int TablePos7 = FilterSize * 6;
125 const int TablePos8 = FilterSize * 7;
126 double*
const TableEnd = Table + ( FilterFracs + 1 ) * FilterSize;
129 if( InterpPoints == 8 )
131 if( ElementSize == 3 )
136 while( p < TableEnd )
139 p[ TablePos3 ], p[ TablePos4 ], p[ TablePos5 ],
140 p[ TablePos6 ], p[ TablePos7 ], p[ TablePos8 ]);
145 #if defined( R8B_SIMD_ISH )
146 shuffle2_3( Table, TableEnd );
150 if( ElementSize == 4 )
155 while( p < TableEnd )
158 p[ TablePos3 ], p[ TablePos4 ], p[ TablePos5 ],
159 p[ TablePos6 ], p[ TablePos7 ], p[ TablePos8 ]);
164 #if defined( R8B_SIMD_ISH )
165 shuffle2_4( Table, TableEnd );
171 if( ElementSize == 2 )
175 while( p < TableEnd )
177 p[ 1 ] = p[ TablePos2 ] - p[ 0 ];
181 #if defined( R8B_SIMD_ISH )
182 shuffle2_2( Table, TableEnd );
187 R8BCONSOLE(
"CDSPFracDelayFilterBank: fracs=%i order=%i taps=%i "
188 "att=%.1f third=%i\n", FilterFracs, ElementSize - 1, FilterLen,
189 ReqAtten, (
int) IsThird );
203 getWinParams( att, aIsThird, tmp );
222 return( FilterFracs );
235 return( Table[ i * FilterSize ]);
274 static const double* getWinParams(
double& att,
const bool aIsThird,
277 static const int Coeffs2Base = 8;
278 static const int Coeffs2Count = 12;
279 static const double Coeffs2[ Coeffs2Count ][ 3 ] = {
280 { 4.1308468534586913, 1.1752580009977263, 55.5446 },
281 { 4.4241520324148826, 1.8004881791443044, 81.4191 },
282 { 5.2615232289173663, 1.8133318236025469, 96.3392 },
283 { 5.9433751227216174, 1.8730186391986436, 111.1315 },
284 { 6.8308658290513815, 1.8549555110340281, 125.4653 },
285 { 7.6648458290312904, 1.8565766090828464, 139.7379 },
286 { 8.2038728664307605, 1.9269521820570166, 154.0532 },
287 { 8.7865150946655142, 1.9775307667441668, 168.2101 },
288 { 9.5945017884101773, 1.9718456992078597, 182.1076 },
289 { 10.5163141145985240, 1.9504067820201083, 195.5668 },
290 { 10.2382465206362470, 2.1608923446870087, 209.0610 },
291 { 10.9976060250714000, 2.1536533525688935, 222.5010 },
294 static const int Coeffs3Base = 6;
295 static const int Coeffs3Count = 10;
296 static const double Coeffs3[ Coeffs3Count ][ 3 ] = {
297 { 3.9888564562781847, 1.5869927184268915, 66.5701 },
298 { 4.6986694038145007, 1.8086068597928262, 86.4715 },
299 { 5.5995071329337822, 1.8930163360942349, 106.1195 },
300 { 6.3627287800257228, 1.9945748322093975, 125.2307 },
301 { 7.4299550711428308, 1.9893400572347544, 144.3469 },
302 { 8.0667715944075642, 2.0928201458699909, 163.4099 },
303 { 8.7469970226288822, 2.1640279784268355, 181.0694 },
304 { 10.0823430069835230, 2.0896678025321922, 199.2880 },
305 { 10.9222206090489510, 2.1221681162186004, 216.6865 },
306 { 21.2017743894772010, 1.1856768080118900, 233.9188 },
309 const double* Params;
314 while( i != Coeffs3Count - 1 && Coeffs3[ i ][ 2 ] < att )
319 Params = &Coeffs3[ i ][ 0 ];
320 att = Coeffs3[ i ][ 2 ];
321 fltlen = Coeffs3Base + i * 2;
325 while( i != Coeffs2Count - 1 && Coeffs2[ i ][ 2 ] < att )
330 Params = &Coeffs2[ i ][ 0 ];
331 att = Coeffs2[ i ][ 2 ];
332 fltlen = Coeffs2Base + i * 2;
345 static void shuffle2_2(
double* p,
double*
const pe )
349 const double t = p[ 2 ];
364 static void shuffle2_3(
double* p,
double*
const pe )
368 const double t1 = p[ 1 ];
369 const double t2 = p[ 2 ];
370 const double t3 = p[ 3 ];
371 const double t4 = p[ 4 ];
388 static void shuffle2_4(
double* p,
double*
const pe )
392 const double t1 = p[ 1 ];
393 const double t2 = p[ 2 ];
394 const double t3 = p[ 3 ];
395 const double t4 = p[ 4 ];
396 const double t5 = p[ 5 ];
397 const double t6 = p[ 6 ];
420 friend class CDSPFracDelayFilterBank;
440 const int aElementSize,
const int aInterpPoints,
441 double ReqAtten,
const bool IsThird,
const bool IsStatic )
450 CDSPFracDelayFilterBank :: roundReqAtten( ReqAtten, IsThird );
456 CDSPFracDelayFilterBank* PrevObj =
R8B_NULL;
457 CDSPFracDelayFilterBank* CurObj = StaticObjects;
461 if( CurObj -> InitFilterFracs == aFilterFracs &&
462 CurObj -> IsThird == IsThird &&
463 CurObj -> ElementSize == aElementSize &&
464 CurObj -> InterpPoints == aInterpPoints &&
465 CurObj -> ReqAtten == ReqAtten )
471 PrevObj -> Next = CurObj -> Next;
472 CurObj -> Next = StaticObjects.unkeep();
473 StaticObjects = CurObj;
480 CurObj = CurObj -> Next;
485 CurObj =
new CDSPFracDelayFilterBank( aFilterFracs, aElementSize,
486 aInterpPoints, ReqAtten, IsThird );
490 CurObj -> Next = StaticObjects.unkeep();
491 StaticObjects = CurObj;
496 CDSPFracDelayFilterBank* PrevObj =
R8B_NULL;
497 CDSPFracDelayFilterBank* CurObj = Objects;
501 if( CurObj -> InitFilterFracs == aFilterFracs &&
502 CurObj -> IsThird == IsThird &&
503 CurObj -> ElementSize == aElementSize &&
504 CurObj -> InterpPoints == aInterpPoints &&
505 CurObj -> ReqAtten == ReqAtten )
513 if( CurObj -> RefCount == 0 )
527 CurObj -> Next = Objects.unkeep();
536 CurObj = CurObj -> Next;
541 CurObj -> RefCount++;
550 PrevObj -> Next = CurObj -> Next;
556 CurObj =
new CDSPFracDelayFilterBank( aFilterFracs, aElementSize,
557 aInterpPoints, ReqAtten, IsThird );
564 CurObj -> Next = Objects.unkeep();
587inline void CDSPFracDelayFilterBank :: unref()
589 R8BSYNC( CDSPFracDelayFilterBankCache :: getStateSync() );
604inline bool findGCD(
double l,
double s,
double& GCD )
610 const double r = l - s;
640 const double DSampleRate,
int& ResInStep,
int& ResOutStep )
644 if( !
findGCD( SSampleRate, DSampleRate, GCD ))
649 const double InStep0 = SSampleRate / GCD;
650 const double OutStep0 = DSampleRate / GCD;
652 if( OutStep0 > 1500.0 )
660 ResInStep = (int) InStep0;
661 ResOutStep = (int) OutStep0;
665 if( InStep0 != ResInStep || OutStep0 != ResOutStep )
704 const double aDstSampleRate,
const double ReqAtten,
705 const bool IsThird,
const double PrevLatency )
706 : SrcSampleRate( aSrcSampleRate )
707 , DstSampleRate( aDstSampleRate )
708 , FracStep( aSrcSampleRate / aDstSampleRate )
715 InitFracPos = PrevLatency;
716 Latency = (int) InitFracPos;
717 InitFracPos -= Latency;
735 const double spos = InitFracPos * OutStep;
736 InitFracPosW = (int) spos;
737 LatencyFrac = ( spos - InitFracPosW ) / InStep;
739 FilterBank = &CDSPFracDelayFilterBankCache :: getFilterBank(
740 OutStep, 1, 2, ReqAtten, IsThird,
false );
745 FilterBank = &CDSPFracDelayFilterBankCache :: getFilterBank(
746 -1, 3, 8, ReqAtten, IsThird,
true );
751 FilterLen = FilterBank -> getFilterLen();
752 fl2 = FilterLen >> 1;
757 R8BASSERT(( 1 << BufLenBits ) >= FilterLen * 3 );
759 static const CConvolveFn FltConvFn0[ 13 ] = {
760 &CDSPFracInterpolator :: convolve0< 6 >,
761 &CDSPFracInterpolator :: convolve0< 8 >,
762 &CDSPFracInterpolator :: convolve0< 10 >,
763 &CDSPFracInterpolator :: convolve0< 12 >,
764 &CDSPFracInterpolator :: convolve0< 14 >,
765 &CDSPFracInterpolator :: convolve0< 16 >,
766 &CDSPFracInterpolator :: convolve0< 18 >,
767 &CDSPFracInterpolator :: convolve0< 20 >,
768 &CDSPFracInterpolator :: convolve0< 22 >,
769 &CDSPFracInterpolator :: convolve0< 24 >,
770 &CDSPFracInterpolator :: convolve0< 26 >,
771 &CDSPFracInterpolator :: convolve0< 28 >,
772 &CDSPFracInterpolator :: convolve0< 30 >
775 convfn = ( IsWhole ? FltConvFn0[ fl2 - 3 ] :
776 &CDSPFracInterpolator :: convolve2 );
778 R8BCONSOLE(
"CDSPFracInterpolator: src=%.2f dst=%.2f taps=%i "
779 "fracs=%i whole=%i third=%i step=%.6f\n", SrcSampleRate,
780 DstSampleRate, FilterLen, ( IsWhole ? OutStep :
781 FilterBank -> getFilterFracs() ), (
int) IsWhole, (
int) IsThird,
782 aSrcSampleRate / aDstSampleRate );
794 const int ilat = fl2 + Latency;
798 return( ilat + (
int) (( InitFracPosW +
799 (
double) ReqOutPos * InStep ) / OutStep +
800 LatencyFrac * InStep / OutStep ));
803 return( ilat + (
int) ( InitFracPos + ReqOutPos * SrcSampleRate /
814 return( LatencyFrac );
821 return( (
int) ceil( MaxInLen * DstSampleRate / SrcSampleRate ) + 1 );
826 LatencyLeft = Latency;
832 memset( &Buf[ ReadPos ], 0,
833 (
size_t) ( BufLen - flb ) *
sizeof( Buf[ 0 ]));
837 InPosFracW = InitFracPosW;
841 InPosFrac = InitFracPos;
843 InPosShift = InitFracPos / SrcSampleRate * DstSampleRate;
847 virtual int process(
double* ip,
int l,
double*& op0 )
850 R8BASSERT( ip != op0 || l == 0 || SrcSampleRate > DstSampleRate );
852 if( LatencyLeft != 0 )
854 if( LatencyLeft >= l )
871 const int b =
min( l,
min( BufLen - WritePos, flb - BufLeft ));
873 double*
const wp1 = Buf + WritePos;
874 memcpy( wp1, ip, (
size_t) b *
sizeof( wp1[ 0 ]));
875 const int ec = flo - WritePos;
879 memcpy( wp1 + BufLen, ip,
880 (
size_t)
min( b, ec ) *
sizeof( wp1[ 0 ]));
884 WritePos = ( WritePos + b ) & BufLenMask;
890 op = ( *this.*convfn )( op );
893 if( !IsWhole && (
int) InPosShift > 1000 )
899 InPosShift = InPosFrac / SrcSampleRate * DstSampleRate;
902 return( (
int) ( op - op0 ));
906 static const int BufLenBits = 8;
914 static const int BufLen = 1 << BufLenBits;
917 static const int BufLenMask = BufLen - 1;
919 double Buf[ BufLen + 29 ];
921 double SrcSampleRate;
922 double DstSampleRate;
972 template<
int fltlen >
973 double* convolve0(
double* op )
976 const int istep = InStep;
977 const int ostep = OutStep;
978 int fpos = InPosFracW;
980 int bl = BufLeft - fl2;
984 const double*
const ftp = &fb[ fpos ];
985 const double*
const rp = Buf + rpos;
988 #if defined( R8B_SSE2 ) && !defined( __INTEL_COMPILER )
990 __m128d s = _mm_setzero_pd();
992 for( i = 0; i < fltlen; i += 2 )
994 const __m128d m = _mm_mul_pd( _mm_load_pd( ftp + i ),
995 _mm_loadu_pd( rp + i ));
997 s = _mm_add_pd( s, m );
1000 _mm_storel_pd( op, _mm_add_pd( s, _mm_shuffle_pd( s, s, 1 )));
1002 #elif defined( R8B_NEON )
1004 float64x2_t s = vdupq_n_f64( 0.0 );
1006 for( i = 0; i < fltlen; i += 2 )
1008 s = vmlaq_f64( s, vld1q_f64( ftp + i ), vld1q_f64( rp + i ));
1011 *op = vaddvq_f64( s );
1017 for( i = 0; i < fltlen; i++ )
1019 s += ftp[ i ] * rp[ i ];
1029 const int PosIncr = fpos / ostep;
1030 fpos -= PosIncr * ostep;
1032 rpos = ( rpos + PosIncr ) & BufLenMask;
1050 double* convolve2(
double* op )
1052 const CDSPFracDelayFilterBank& fb = *FilterBank;
1053 const int fltlen = FilterLen;
1055 const double fs = FracStep;
1056 int ipos = InPosInt;
1057 double fpos = InPosFrac;
1058 double psh = InPosShift;
1060 int bl = BufLeft - fl2;
1064 double x = fpos * ffracs;
1065 const int fti = (int) x;
1066 const double* ftp = &fb[ fti ];
1069 const double*
const rp = Buf + rpos;
1070 const double x2d = x * x;
1073 #if defined( R8B_SSE2 ) && defined( R8B_SIMD_ISH )
1075 const __m128d x1 = _mm_set1_pd( x );
1076 const __m128d x2 = _mm_set1_pd( x2d );
1077 __m128d s = _mm_setzero_pd();
1079 for( i = 0; i < fltlen; i += 2 )
1081 const __m128d ftp2 = _mm_load_pd( ftp + 2 );
1082 const __m128d xx1 = _mm_mul_pd( ftp2, x1 );
1083 const __m128d ftp4 = _mm_load_pd( ftp + 4 );
1084 const __m128d xx2 = _mm_mul_pd( ftp4, x2 );
1085 const __m128d ftp0 = _mm_load_pd( ftp );
1088 const __m128d rpi = _mm_loadu_pd( rp + i );
1089 const __m128d xxs = _mm_add_pd( ftp0, _mm_add_pd( xx1, xx2 ));
1091 s = _mm_add_pd( s, _mm_mul_pd( rpi, xxs ));
1094 _mm_storel_pd( op, _mm_add_pd( s, _mm_shuffle_pd( s, s, 1 )));
1096 #elif defined( R8B_NEON ) && defined( R8B_SIMD_ISH )
1098 const float64x2_t x1 = vdupq_n_f64( x );
1099 const float64x2_t x2 = vdupq_n_f64( x2d );
1100 float64x2_t s = vdupq_n_f64( 0.0 );
1102 for( i = 0; i < fltlen; i += 2 )
1104 const float64x2_t ftp2 = vld1q_f64( ftp + 2 );
1105 const float64x2_t xx1 = vmulq_f64( ftp2, x1 );
1106 const float64x2_t ftp4 = vld1q_f64( ftp + 4 );
1107 const float64x2_t xx2 = vmulq_f64( ftp4, x2 );
1108 const float64x2_t ftp0 = vld1q_f64( ftp );
1111 const float64x2_t rpi = vld1q_f64( rp + i );
1112 const float64x2_t xxs = vaddq_f64( ftp0,
1113 vaddq_f64( xx1, xx2 ));
1115 s = vmlaq_f64( s, rpi, xxs );
1118 *op = vaddvq_f64( s );
1124 for( i = 0; i < fltlen; i++ )
1126 s += ( ftp[ 0 ] + ftp[ 1 ] * x + ftp[ 2 ] * x2d ) * rp[ i ];
1137 const double NextInPos = psh * fs;
1138 const int NextInPosInt = (int) NextInPos;
1139 const int PosIncr = NextInPosInt - ipos;
1141 fpos = NextInPos - NextInPosInt;
1142 ipos = NextInPosInt;
1145 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:833
#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.
Definition r8bbase.h:213
#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_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:639
T min(const T &v1, const T &v2)
Returns minimum of two values.
Definition r8bbase.h:1257
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:1158
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:1192
bool findGCD(double l, double s, double &GCD)
Interatively searches for a greatest common denominator (GCD) of 2 numbers.
Definition CDSPFracInterpolator.h:604
void normalizeFIRFilter(double *const p, const int l, const double DCGain, const int pstep=1)
FIR filter's gain normalization.
Definition r8bbase.h:1112
Sinc function-based fractional delay filter bank class.
Definition CDSPFracInterpolator.h:40
void unref()
Reduces reference count to this object.
Definition CDSPFracInterpolator.h:587
int getFilterFracs() const
Returns the number of fractional positions sampled by the bank.
Definition CDSPFracInterpolator.h:220
const double & operator[](const int i) const
Returns reference to the filter.
Definition CDSPFracInterpolator.h:231
static void roundReqAtten(double &att, const bool aIsThird)
Rounds the specified attenuation to the nearest effective value.
Definition CDSPFracInterpolator.h:200
int getFilterLen() const
Returns the length of the filter, in samples (taps). Always an even number, not less than 6.
Definition CDSPFracInterpolator.h:211
CDSPFracDelayFilterBank(const int aFilterFracs, const int aElementSize, const int aInterpPoints, const double aReqAtten, const bool aIsThird)
Initializes the filter bank object.
Definition CDSPFracInterpolator.h:63
Fractional delay filter cache class.
Definition CDSPFracInterpolator.h:417
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:439
static CSyncObject & getStateSync()
Returns reference to global filter bank cache sync object.
Definition CDSPFracInterpolator.h:575
Fractional delay filter bank-based interpolator class.
Definition CDSPFracInterpolator.h:687
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:703
virtual int process(double *ip, int l, double *&op0)
Performs DSP processing.
Definition CDSPFracInterpolator.h:847
virtual int getInLenBeforeOutPos(int ReqOutPos) const
Returns the number of input samples required to advance to the specified output sample position (so t...
Definition CDSPFracInterpolator.h:787
virtual int getLatency() const
Return the latency, in samples, which is present in the output signal.
Definition CDSPFracInterpolator.h:807
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:817
virtual double getLatencyFrac() const
Returns fractional latency, in samples, which is present in the output signal.
Definition CDSPFracInterpolator.h:812
virtual void clear()
Clears (resets) the state of this object and returns it to the state after construction.
Definition CDSPFracInterpolator.h:824
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:457
Reference "keeper" class with automatic unref() call.
Definition r8bbase.h:557
CDSPProcessor * Next
Definition r8bbase.h:652
Multi-threaded synchronization object class.
Definition r8bbase.h:691