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