r8brain-free-src
High-quality pro audio sample rate converter library
 
Loading...
Searching...
No Matches
CDSPFracInterpolator.h
Go to the documentation of this file.
1//$ nobt
2//$ nocpp
3
15
16#ifndef R8B_CDSPFRACINTERPOLATOR_INCLUDED
17#define R8B_CDSPFRACINTERPOLATOR_INCLUDED
18
19#include "CDSPSincFilterGen.h"
20#include "CDSPProcessor.h"
21
22namespace r8b {
23
24#if R8B_FLTTEST
25 extern int InterpFilterFracs;
27#endif // R8B_FLTTEST
28
37
39{
41
42 friend class CDSPFracDelayFilterBankCache;
43
44public:
60
61 CDSPFracDelayFilterBank( const int aFilterFracs, const int aElementSize,
62 const int aInterpPoints, const double aReqAtten, const bool aIsThird )
63 : InitFilterFracs( aFilterFracs )
64 , ElementSize( aElementSize )
65 , InterpPoints( aInterpPoints )
66 , ReqAtten( aReqAtten )
67 , IsThird( aIsThird )
68 , Next( R8B_NULL )
69 , RefCount( 1 )
70 {
71 R8BASSERT( ElementSize >= 1 && ElementSize <= 4 );
72
73 // Kaiser window function Params, for half and third-band.
74
75 const double* const Params = getWinParams( ReqAtten, IsThird,
76 FilterLen );
77
78 FilterSize = FilterLen * ElementSize;
79
80 if( InitFilterFracs == -1 )
81 {
82 FilterFracs = (int) ceil( pow( 6.4, ReqAtten / 50.0 ));
83
84 #if R8B_FLTTEST
85
86 if( InterpFilterFracs != -1 )
87 {
88 FilterFracs = InterpFilterFracs;
89 }
90
91 #endif // R8B_FLTTEST
92 }
93 else
94 {
95 FilterFracs = InitFilterFracs;
96 }
97
98 Table.alloc( FilterSize * ( FilterFracs + InterpPoints ));
99
101 sinc.Len2 = FilterLen / 2;
102
103 double* p = Table;
104 const int pc2 = InterpPoints / 2;
105 int i;
106
107 for( i = -pc2 + 1; i <= FilterFracs + pc2; i++ )
108 {
109 sinc.FracDelay = (double) ( FilterFracs - i ) / FilterFracs;
110 sinc.initFrac( CDSPSincFilterGen :: wftKaiser, Params, true );
111 sinc.generateFrac( p, &CDSPSincFilterGen :: calcWindowKaiser,
112 ElementSize );
113
114 normalizeFIRFilter( p, FilterLen, 1.0, ElementSize );
115 p += FilterSize;
116 }
117
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;
126 p = Table;
127
128 if( InterpPoints == 8 )
129 {
130 if( ElementSize == 3 )
131 {
132 // Calculate 2nd order spline (polynomial) interpolation
133 // coefficients using 8 points.
134
135 while( p < TableEnd )
136 {
137 calcSpline2p8Coeffs( p, p[ 0 ], p[ TablePos2 ],
138 p[ TablePos3 ], p[ TablePos4 ], p[ TablePos5 ],
139 p[ TablePos6 ], p[ TablePos7 ], p[ TablePos8 ]);
140
141 p += ElementSize;
142 }
143
144 #if defined( R8B_SIMD_ISH )
145 shuffle2_3( Table, TableEnd );
146 #endif // SIMD
147 }
148 else
149 if( ElementSize == 4 )
150 {
151 // Calculate 3rd order spline (polynomial) interpolation
152 // coefficients using 8 points.
153
154 while( p < TableEnd )
155 {
156 calcSpline3p8Coeffs( p, p[ 0 ], p[ TablePos2 ],
157 p[ TablePos3 ], p[ TablePos4 ], p[ TablePos5 ],
158 p[ TablePos6 ], p[ TablePos7 ], p[ TablePos8 ]);
159
160 p += ElementSize;
161 }
162
163 #if defined( R8B_SIMD_ISH )
164 shuffle2_4( Table, TableEnd );
165 #endif // SIMD
166 }
167 }
168 else
169 {
170 if( ElementSize == 2 )
171 {
172 // Calculate linear interpolation coefficients.
173
174 while( p < TableEnd )
175 {
176 p[ 1 ] = p[ TablePos2 ] - p[ 0 ];
177 p += ElementSize;
178 }
179
180 #if defined( R8B_SIMD_ISH )
181 shuffle2_2( Table, TableEnd );
182 #endif // SIMD
183 }
184 }
185
186 R8BCONSOLE( "CDSPFracDelayFilterBank: fracs=%i order=%i taps=%i "
187 "att=%.1f third=%i\n", FilterFracs, ElementSize - 1, FilterLen,
188 ReqAtten, (int) IsThird );
189 }
190
192 {
193 delete Next;
194 }
195
203
204 static void roundReqAtten( double& att, const bool aIsThird )
205 {
206 int tmp;
207 getWinParams( att, aIsThird, tmp );
208 }
209
214
215 int getFilterLen() const
216 {
217 return( FilterLen );
218 }
219
223
224 int getFilterFracs() const
225 {
226 return( FilterFracs );
227 }
228
234
235 const double& operator []( const int i ) const
236 {
237 R8BASSERT( i >= 0 && i <= FilterFracs );
238
239 return( Table[ i * FilterSize ]);
240 }
241
248
249 void unref();
250
251private:
252 int FilterLen;
253 int FilterFracs;
254 int InitFilterFracs;
256 int ElementSize;
257 int InterpPoints;
258 double ReqAtten;
259 bool IsThird;
260 int FilterSize;
266 int RefCount;
268
278
279 static const double* getWinParams( double& att, const bool aIsThird,
280 int& fltlen )
281 {
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 }, // 0.0256
286 { 4.4241520324148826, 1.8004881791443044, 81.4191 }, // 0.0886
287 { 5.2615232289173663, 1.8133318236025469, 96.3392 }, // 0.0481
288 { 5.9433751227216174, 1.8730186391986436, 111.1315 }, // 0.0264
289 { 6.8308658290513815, 1.8549555110340281, 125.4653 }, // 0.0146
290 { 7.6648458290312904, 1.8565766090828464, 139.7379 }, // 0.0081
291 { 8.2038728664307605, 1.9269521820570166, 154.0532 }, // 0.0045
292 { 8.7865150946655142, 1.9775307667441668, 168.2101 }, // 0.0025
293 { 9.5945017884101773, 1.9718456992078597, 182.1076 }, // 0.0014
294 { 10.5163141145985240, 1.9504067820201083, 195.5668 }, // 0.0008
295 { 10.2382465206362470, 2.1608923446870087, 209.0610 }, // 0.0004
296 { 10.9976060250714000, 2.1536533525688935, 222.5010 }, // 0.0003
297 };
298
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 }, // 0.0467
303 { 4.6986694038145007, 1.8086068597928262, 86.4715 }, // 0.0136
304 { 5.5995071329337822, 1.8930163360942349, 106.1195 }, // 0.0040
305 { 6.3627287800257228, 1.9945748322093975, 125.2307 }, // 0.0012
306 { 7.4299550711428308, 1.9893400572347544, 144.3469 }, // 0.0004
307 { 8.0667715944075642, 2.0928201458699909, 163.4099 }, // 0.0001
308 { 8.7469970226288822, 2.1640279784268355, 181.0694 }, // 0.0000
309 { 10.0823430069835230, 2.0896678025321922, 199.2880 }, // 0.0000
310 { 10.9222206090489510, 2.1221681162186004, 216.6865 }, // 0.0000
311 { 21.2017743894772010, 1.1856768080118900, 233.9188 }, // 0.0000
312 };
313
314 const double* Params;
315 int i = 0;
316
317 if( aIsThird )
318 {
319 while( i != Coeffs3Count - 1 && Coeffs3[ i ][ 2 ] < att )
320 {
321 i++;
322 }
323
324 Params = &Coeffs3[ i ][ 0 ];
325 att = Coeffs3[ i ][ 2 ];
326 fltlen = Coeffs3Base + i * 2;
327 }
328 else
329 {
330 while( i != Coeffs2Count - 1 && Coeffs2[ i ][ 2 ] < att )
331 {
332 i++;
333 }
334
335 Params = &Coeffs2[ i ][ 0 ];
336 att = Coeffs2[ i ][ 2 ];
337 fltlen = Coeffs2Base + i * 2;
338 }
339
340 return( Params );
341 }
342
349
350 static void shuffle2_2( double* p, double* const pe )
351 {
352 while( p != pe )
353 {
354 const double t = p[ 2 ];
355 p[ 2 ] = p[ 1 ];
356 p[ 1 ] = t;
357
358 p += 4;
359 }
360 }
361
368
369 static void shuffle2_3( double* p, double* const pe )
370 {
371 while( p != pe )
372 {
373 const double t1 = p[ 1 ];
374 const double t2 = p[ 2 ];
375 const double t3 = p[ 3 ];
376 const double t4 = p[ 4 ];
377 p[ 1 ] = t3;
378 p[ 2 ] = t1;
379 p[ 3 ] = t4;
380 p[ 4 ] = t2;
381
382 p += 6;
383 }
384 }
385
392
393 static void shuffle2_4( double* p, double* const pe )
394 {
395 while( p != pe )
396 {
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 ];
403 p[ 1 ] = t4;
404 p[ 2 ] = t1;
405 p[ 3 ] = t5;
406 p[ 4 ] = t2;
407 p[ 5 ] = t6;
408 p[ 6 ] = t3;
409
410 p += 8;
411 }
412 }
413};
414
420
422{
424
425 friend class CDSPFracDelayFilterBank;
426
427public:
443
444 static CDSPFracDelayFilterBank& getFilterBank( const int aFilterFracs,
445 const int aElementSize, const int aInterpPoints,
446 double ReqAtten, const bool IsThird, const bool IsStatic )
447 {
449 // The chain of cached objects.
451 // The chain of static objects.
452 R8B_EXITDTOR static int ObjCount = 0; // The number of objects
453 // currently present in the Objects cache.
454
455 CDSPFracDelayFilterBank :: roundReqAtten( ReqAtten, IsThird );
456
458
459 if( IsStatic )
460 {
461 CDSPFracDelayFilterBank* PrevObj = R8B_NULL;
462 CDSPFracDelayFilterBank* CurObj = StaticObjects;
463
464 while( CurObj != R8B_NULL )
465 {
466 if( CurObj -> InitFilterFracs == aFilterFracs &&
467 CurObj -> IsThird == IsThird &&
468 CurObj -> ElementSize == aElementSize &&
469 CurObj -> InterpPoints == aInterpPoints &&
470 CurObj -> ReqAtten == ReqAtten )
471 {
472 if( PrevObj != R8B_NULL )
473 {
474 // Move the object to the top of the list.
475
476 PrevObj -> Next = CurObj -> Next;
477 CurObj -> Next = StaticObjects.unkeep();
478 StaticObjects = CurObj;
479 }
480
481 return( *CurObj );
482 }
483
484 PrevObj = CurObj;
485 CurObj = CurObj -> Next;
486 }
487
488 // Create a new filter bank and build it.
489
490 CurObj = new CDSPFracDelayFilterBank( aFilterFracs, aElementSize,
491 aInterpPoints, ReqAtten, IsThird );
492
493 // Insert the bank at the start of the list.
494
495 CurObj -> Next = StaticObjects.unkeep();
496 StaticObjects = CurObj;
497
498 return( *CurObj );
499 }
500
501 CDSPFracDelayFilterBank* PrevObj = R8B_NULL;
502 CDSPFracDelayFilterBank* CurObj = Objects;
503
504 while( CurObj != R8B_NULL )
505 {
506 if( CurObj -> InitFilterFracs == aFilterFracs &&
507 CurObj -> IsThird == IsThird &&
508 CurObj -> ElementSize == aElementSize &&
509 CurObj -> InterpPoints == aInterpPoints &&
510 CurObj -> ReqAtten == ReqAtten )
511 {
512 break;
513 }
514
515 if( CurObj -> Next == R8B_NULL &&
516 ObjCount >= R8B_FRACBANK_CACHE_MAX )
517 {
518 if( CurObj -> RefCount == 0 )
519 {
520 // Delete the last bank which is not used.
521
522 PrevObj -> Next = R8B_NULL;
523 delete CurObj;
524 ObjCount--;
525 }
526 else
527 {
528 // Move the last bank to the top of the list since it
529 // seems to be in use for a long time.
530
531 PrevObj -> Next = R8B_NULL;
532 CurObj -> Next = Objects.unkeep();
533 Objects = CurObj;
534 }
535
536 CurObj = R8B_NULL;
537 break;
538 }
539
540 PrevObj = CurObj;
541 CurObj = CurObj -> Next;
542 }
543
544 if( CurObj != R8B_NULL )
545 {
546 CurObj -> RefCount++;
547
548 if( PrevObj == R8B_NULL )
549 {
550 return( *CurObj );
551 }
552
553 // Remove the bank from the list temporarily.
554
555 PrevObj -> Next = CurObj -> Next;
556 }
557 else
558 {
559 // Create a new filter bank (with RefCount == 1) and build it.
560
561 CurObj = new CDSPFracDelayFilterBank( aFilterFracs, aElementSize,
562 aInterpPoints, ReqAtten, IsThird );
563
564 ObjCount++;
565 }
566
567 // Insert the bank at the start of the list.
568
569 CurObj -> Next = Objects.unkeep();
570 Objects = CurObj;
571
572 return( *CurObj );
573 }
574
575protected:
579
581 {
582 R8B_EXITDTOR static CSyncObject StateSync;
583
584 return( StateSync );
585 }
586};
587
588// ---------------------------------------------------------------------------
589// CDSPFracDelayFilterBank PUBLIC
590// ---------------------------------------------------------------------------
591
592inline void CDSPFracDelayFilterBank :: unref()
593{
594 R8BSYNC( CDSPFracDelayFilterBankCache :: getStateSync() );
595
596 RefCount--;
597}
598
608
609inline bool findGCD( double l, double s, double& GCD )
610{
611 int it = 0;
612
613 while( ++it < 150 )
614 {
615 const double r = l - s;
616
617 if( r == 0.0 )
618 {
619 GCD = s;
620 return( s > 0.0 );
621 }
622
623 l = s;
624 s = fabs( r );
625 }
626
627 return( false );
628}
629
643
644inline bool getWholeStepping( const double SSampleRate,
645 const double DSampleRate, int& ResInStep, int& ResOutStep )
646{
647 double GCD;
648
649 if( !findGCD( SSampleRate, DSampleRate, GCD ))
650 {
651 return( false );
652 }
653
654 const double InStep0 = SSampleRate / GCD;
655 const double OutStep0 = DSampleRate / GCD;
656
657 if( OutStep0 > 1500.0 )
658 {
659 // Do not allow large output stepping due to low cache
660 // performance of large filter banks.
661
662 return( false );
663 }
664
665 ResInStep = (int) InStep0;
666 ResOutStep = (int) OutStep0;
667
668 // Check for double-to-int precision and overflows.
669
670 if( InStep0 != ResInStep || OutStep0 != ResOutStep )
671 {
672 return( false );
673 }
674
675 return( true );
676}
677
692
693class CDSPFracInterpolator : public CDSPProcessor
694{
695public:
709
710 CDSPFracInterpolator( const double aSrcSampleRate,
711 const double aDstSampleRate, const double ReqAtten,
712 const bool IsThird, const double PrevLatency )
713 : SrcSampleRate( aSrcSampleRate )
714 , DstSampleRate( aDstSampleRate )
716 , FracStep( aSrcSampleRate / aDstSampleRate )
717 #endif // R8B_FASTTIMING
718 {
719 R8BASSERT( SrcSampleRate > 0.0 );
720 R8BASSERT( DstSampleRate > 0.0 );
721 R8BASSERT( PrevLatency >= 0.0 );
722 R8BASSERT( BufLenBits >= 5 );
723
724 InitFracPos = PrevLatency;
725 Latency = (int) InitFracPos;
726 InitFracPos -= Latency;
727
728 R8BASSERT( Latency >= 0 );
729
730 #if R8B_FLTTEST
731
732 IsWhole = false;
733 LatencyFrac = 0.0;
734 FilterBank = new CDSPFracDelayFilterBank( -1, 3, 8, ReqAtten,
735 IsThird );
736
737 #else // R8B_FLTTEST
738
739 IsWhole = getWholeStepping( SrcSampleRate, DstSampleRate, InStep,
740 OutStep );
741
742 if( IsWhole )
743 {
744 const double spos = InitFracPos * OutStep;
745 InitFracPosW = (int) spos;
746 LatencyFrac = ( spos - InitFracPosW ) / InStep;
747
748 FilterBank = &CDSPFracDelayFilterBankCache :: getFilterBank(
749 OutStep, 1, 2, ReqAtten, IsThird, false );
750 }
751 else
752 {
753 LatencyFrac = 0.0;
754 FilterBank = &CDSPFracDelayFilterBankCache :: getFilterBank(
755 -1, 3, 8, ReqAtten, IsThird, true );
756 }
757
758 #endif // R8B_FLTTEST
759
760 FilterLen = FilterBank -> getFilterLen();
761 fl2 = FilterLen >> 1;
762 fll = fl2 - 1;
763 flo = fll + fl2;
764 flb = BufLen - fll;
765
766 R8BASSERT(( 1 << BufLenBits ) >= FilterLen * 3 );
767
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 >
782 };
783
784 convfn = ( IsWhole ? FltConvFn0[ fl2 - 3 ] :
785 &CDSPFracInterpolator :: convolve2 );
786
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 );
792
793 clear();
794 }
795
796 virtual ~CDSPFracInterpolator()
797 {
798 #if R8B_FLTTEST
799 delete FilterBank;
800 #else // R8B_FLTTEST
801 FilterBank -> unref();
802 #endif // R8B_FLTTEST
803 }
804
805 virtual int getInLenBeforeOutPos( const int ReqOutPos ) const
806 {
807 const int ilat = fl2 + Latency;
808
809 if( IsWhole )
810 {
811 return( ilat + (int) (( InitFracPosW +
812 (double) ReqOutPos * InStep ) / OutStep +
813 LatencyFrac * InStep / OutStep ));
814 }
815
816 return( ilat + (int) ( InitFracPos + ReqOutPos * SrcSampleRate /
817 DstSampleRate ));
818 }
819
820 virtual int getLatency() const
821 {
822 return( 0 );
823 }
824
825 virtual double getLatencyFrac() const
826 {
827 return( LatencyFrac );
828 }
829
830 virtual int getMaxOutLen( const int MaxInLen ) const
831 {
832 R8BASSERT( MaxInLen >= 0 );
833
834 return( (int) ceil( MaxInLen * DstSampleRate / SrcSampleRate ) + 1 );
835 }
836
837 virtual void clear()
838 {
839 LatencyLeft = Latency;
840 BufLeft = 0;
841 WritePos = 0;
842 ReadPos = flb; // Set "read" position to account for filter's
843 // latency at zero fractional delay.
844
845 memset( &Buf[ ReadPos ], 0,
846 (size_t) ( BufLen - flb ) * sizeof( Buf[ 0 ]));
847
848 if( IsWhole )
849 {
850 InPosFracW = InitFracPosW;
851 }
852 else
853 {
854 InPosFrac = InitFracPos;
855
856 #if !R8B_FASTTIMING
857 InCounter = 0;
858 InPosInt = 0;
859 InPosShift = InitFracPos * DstSampleRate / SrcSampleRate;
860 #endif // !R8B_FASTTIMING
861 }
862 }
863
864 virtual int process( double* ip, int l, double*& op0 )
865 {
866 R8BASSERT( l >= 0 );
867 R8BASSERT( ip != op0 || l == 0 || SrcSampleRate > DstSampleRate );
868
869 if( LatencyLeft != 0 )
870 {
871 if( LatencyLeft >= l )
872 {
873 LatencyLeft -= l;
874 return( 0 );
875 }
876
877 l -= LatencyLeft;
878 ip += LatencyLeft;
879 LatencyLeft = 0;
880 }
881
882 double* op = op0;
883
884 while( l > 0 )
885 {
886 // Copy new input samples to the ring buffer.
887
888 const int b = min( l, min( BufLen - WritePos, flb - BufLeft ));
889
890 double* const wp1 = Buf + WritePos;
891 memcpy( wp1, ip, (size_t) b * sizeof( wp1[ 0 ]));
892 const int ec = flo - WritePos;
893
894 if( ec > 0 )
895 {
896 memcpy( wp1 + BufLen, ip,
897 (size_t) min( b, ec ) * sizeof( wp1[ 0 ]));
898 }
899
900 ip += b;
901 WritePos = ( WritePos + b ) & BufLenMask;
902 l -= b;
903 BufLeft += b;
904
905 // Produce as many output samples as possible.
906
907 op = ( *this.*convfn )( op );
908 }
909
910 #if !R8B_FASTTIMING
911
912 if( !IsWhole && InCounter > 1000 )
913 {
914 // Reset the interpolation position counter to achieve a higher
915 // sample-timing precision.
916
917 InCounter = 0;
918 InPosInt = 0;
919 InPosShift = InPosFrac * DstSampleRate / SrcSampleRate;
920 }
921
922 #endif // !R8B_FASTTIMING
923
924 return( (int) ( op - op0 ));
925 }
926
927private:
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;
945 double InitFracPos;
947 int InitFracPosW;
949 int Latency;
950 double LatencyFrac;
952 int FilterLen;
953 int fll;
954 int fl2;
955 int flo;
956 int flb;
957 int InStep;
958 int OutStep;
960 int LatencyLeft;
961 int BufLeft;
962 int WritePos;
964 int ReadPos;
965 int InPosFracW;
968 double InPosFrac;
969
970#if R8B_FASTTIMING
971 double FracStep;
972#else // R8B_FASTTIMING
973 int InCounter;
974 int InPosInt;
975 double InPosShift;
976#endif // R8B_FASTTIMING
977
978 CDSPFracDelayFilterBank* FilterBank;
980 bool IsWhole;
981
982 typedef double*( CDSPFracInterpolator ::* CConvolveFn )( double* op );
984 CConvolveFn convfn;
985
993
994 template< int fltlen >
995 double* convolve0( double* op )
996 {
997 const CDSPFracDelayFilterBank& fb = *FilterBank;
998 const int istep = InStep;
999 const int ostep = OutStep;
1000 int fpos = InPosFracW;
1001 int rpos = ReadPos;
1002 int bl = BufLeft - fl2;
1003
1004 while( bl > 0 )
1005 {
1006 const double* const ftp = &fb[ fpos ];
1007 const double* const rp = Buf + rpos;
1008 int i;
1009
1010 #if defined( R8B_SSE2 ) && !defined( __INTEL_COMPILER )
1011
1012 __m128d s = _mm_setzero_pd();
1013
1014 for( i = 0; i < fltlen; i += 2 )
1015 {
1016 const __m128d m = _mm_mul_pd( _mm_load_pd( ftp + i ),
1017 _mm_loadu_pd( rp + i ));
1018
1019 s = _mm_add_pd( s, m );
1020 }
1021
1022 _mm_storel_pd( op, _mm_add_pd( s, _mm_shuffle_pd( s, s, 1 )));
1023
1024 #elif defined( R8B_NEON )
1025
1026 float64x2_t s = vdupq_n_f64( 0.0 );
1027
1028 for( i = 0; i < fltlen; i += 2 )
1029 {
1030 s = vmlaq_f64( s, vld1q_f64( ftp + i ), vld1q_f64( rp + i ));
1031 }
1032
1033 *op = vaddvq_f64( s );
1034
1035 #else // SIMD
1036
1037 double s = 0.0;
1038
1039 for( i = 0; i < fltlen; i++ )
1040 {
1041 s += ftp[ i ] * rp[ i ];
1042 }
1043
1044 *op = s;
1045
1046 #endif // SIMD
1047
1048 op++;
1049
1050 fpos += istep;
1051 const int PosIncr = fpos / ostep;
1052 fpos -= PosIncr * ostep;
1053
1054 rpos = ( rpos + PosIncr ) & BufLenMask;
1055 bl -= PosIncr;
1056 }
1057
1058 BufLeft = bl + fl2;
1059 ReadPos = rpos;
1060 InPosFracW = fpos;
1061
1062 return( op );
1063 }
1064
1071
1072 double* convolve2( double* op )
1073 {
1074 const CDSPFracDelayFilterBank& fb = *FilterBank;
1075 const int fltlen = FilterLen;
1076 const double ssr = SrcSampleRate;
1077 const double dsr = DstSampleRate;
1078 double fpos = InPosFrac;
1079 int rpos = ReadPos;
1080 int bl = BufLeft - fl2;
1081
1082 while( bl > 0 )
1083 {
1084 double x = fpos * fb.getFilterFracs();
1085 const int fti = (int) x; // Function table index.
1086 x -= fti; // Coefficient for interpolation between adjacent
1087 // fractional delay filters.
1088 const double x2d = x * x;
1089 const double* ftp = &fb[ fti ];
1090 const double* const rp = Buf + rpos;
1091 int i;
1092
1093 #if defined( R8B_SSE2 ) && defined( R8B_SIMD_ISH )
1094
1095 const __m128d x1 = _mm_set1_pd( x );
1096 const __m128d x2 = _mm_set1_pd( x2d );
1097 __m128d s = _mm_setzero_pd();
1098
1099 for( i = 0; i < fltlen; i += 2 )
1100 {
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 );
1106 ftp += 6;
1107
1108 const __m128d rpi = _mm_loadu_pd( rp + i );
1109 const __m128d xxs = _mm_add_pd( ftp0, _mm_add_pd( xx1, xx2 ));
1110
1111 s = _mm_add_pd( s, _mm_mul_pd( rpi, xxs ));
1112 }
1113
1114 _mm_storel_pd( op, _mm_add_pd( s, _mm_shuffle_pd( s, s, 1 )));
1115
1116 #elif defined( R8B_NEON ) && defined( R8B_SIMD_ISH )
1117
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 );
1121
1122 for( i = 0; i < fltlen; i += 2 )
1123 {
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 );
1129 ftp += 6;
1130
1131 const float64x2_t rpi = vld1q_f64( rp + i );
1132 const float64x2_t xxs = vaddq_f64( ftp0,
1133 vaddq_f64( xx1, xx2 ));
1134
1135 s = vmlaq_f64( s, rpi, xxs );
1136 }
1137
1138 *op = vaddvq_f64( s );
1139
1140 #else // SIMD
1141
1142 double s = 0.0;
1143
1144 for( i = 0; i < fltlen; i++ )
1145 {
1146 s += ( ftp[ 0 ] + ftp[ 1 ] * x + ftp[ 2 ] * x2d ) * rp[ i ];
1147 ftp += 3;
1148 }
1149
1150 *op = s;
1151
1152 #endif // SIMD
1153
1154 op++;
1155
1156 #if R8B_FASTTIMING
1157
1158 fpos += FracStep;
1159 const int PosIncr = (int) fpos;
1160 fpos -= PosIncr;
1161
1162 #else // R8B_FASTTIMING
1163
1164 InCounter++;
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;
1170
1171 #endif // R8B_FASTTIMING
1172
1173 rpos = ( rpos + PosIncr ) & BufLenMask;
1174 bl -= PosIncr;
1175 }
1176
1177 BufLeft = bl + fl2;
1178 ReadPos = rpos;
1179 InPosFrac = fpos;
1180
1181 return( op );
1182 }
1183};
1184
1185// ---------------------------------------------------------------------------
1186
1187} // namespace r8b
1188
1189#endif // R8B_CDSPFRACINTERPOLATOR_INCLUDED
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