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 ResInStep = (int) InStep0;
656 const double OutStep0 = DSampleRate / GCD;
657 ResOutStep = (int) OutStep0;
658
659 if( InStep0 != ResInStep || OutStep0 != ResOutStep )
660 {
661 return( false );
662 }
663
664 if( ResOutStep > 1500 )
665 {
666 // Do not allow large output stepping due to low cache
667 // performance of large filter banks.
668
669 return( false );
670 }
671
672 return( true );
673}
674
689
690class CDSPFracInterpolator : public CDSPProcessor
691{
692public:
706
707 CDSPFracInterpolator( const double aSrcSampleRate,
708 const double aDstSampleRate, const double ReqAtten,
709 const bool IsThird, const double PrevLatency )
710 : SrcSampleRate( aSrcSampleRate )
711 , DstSampleRate( aDstSampleRate )
713 , FracStep( aSrcSampleRate / aDstSampleRate )
714 #endif // R8B_FASTTIMING
715 {
716 R8BASSERT( SrcSampleRate > 0.0 );
717 R8BASSERT( DstSampleRate > 0.0 );
718 R8BASSERT( PrevLatency >= 0.0 );
719 R8BASSERT( BufLenBits >= 5 );
720
721 InitFracPos = PrevLatency;
722 Latency = (int) InitFracPos;
723 InitFracPos -= Latency;
724
725 R8BASSERT( Latency >= 0 );
726
727 #if R8B_FLTTEST
728
729 IsWhole = false;
730 LatencyFrac = 0.0;
731 FilterBank = new CDSPFracDelayFilterBank( -1, 3, 8, ReqAtten,
732 IsThird );
733
734 #else // R8B_FLTTEST
735
736 IsWhole = getWholeStepping( SrcSampleRate, DstSampleRate, InStep,
737 OutStep );
738
739 if( IsWhole )
740 {
741 const double spos = InitFracPos * OutStep;
742 InitFracPosW = (int) spos;
743 LatencyFrac = ( spos - InitFracPosW ) / InStep;
744
745 FilterBank = &CDSPFracDelayFilterBankCache :: getFilterBank(
746 OutStep, 1, 2, ReqAtten, IsThird, false );
747 }
748 else
749 {
750 LatencyFrac = 0.0;
751 FilterBank = &CDSPFracDelayFilterBankCache :: getFilterBank(
752 -1, 3, 8, ReqAtten, IsThird, true );
753 }
754
755 #endif // R8B_FLTTEST
756
757 FilterLen = FilterBank -> getFilterLen();
758 fl2 = FilterLen >> 1;
759 fll = fl2 - 1;
760 flo = fll + fl2;
761 flb = BufLen - fll;
762
763 R8BASSERT(( 1 << BufLenBits ) >= FilterLen * 3 );
764
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 >
779 };
780
781 convfn = ( IsWhole ? FltConvFn0[ fl2 - 3 ] :
782 &CDSPFracInterpolator :: convolve2 );
783
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 );
789
790 clear();
791 }
792
793 virtual ~CDSPFracInterpolator()
794 {
795 #if R8B_FLTTEST
796 delete FilterBank;
797 #else // R8B_FLTTEST
798 FilterBank -> unref();
799 #endif // R8B_FLTTEST
800 }
801
802 virtual int getInLenBeforeOutPos( const int ReqOutPos ) const
803 {
804 const int ilat = fl2 + Latency;
805
806 if( IsWhole )
807 {
808 return( ilat + (int) (( InitFracPosW +
809 (double) ReqOutPos * InStep ) / OutStep +
810 LatencyFrac * InStep / OutStep ));
811 }
812
813 return( ilat + (int) ( InitFracPos + ReqOutPos * SrcSampleRate /
814 DstSampleRate ));
815 }
816
817 virtual int getLatency() const
818 {
819 return( 0 );
820 }
821
822 virtual double getLatencyFrac() const
823 {
824 return( LatencyFrac );
825 }
826
827 virtual int getMaxOutLen( const int MaxInLen ) const
828 {
829 R8BASSERT( MaxInLen >= 0 );
830
831 return( (int) ceil( MaxInLen * DstSampleRate / SrcSampleRate ) + 1 );
832 }
833
834 virtual void clear()
835 {
836 LatencyLeft = Latency;
837 BufLeft = 0;
838 WritePos = 0;
839 ReadPos = flb; // Set "read" position to account for filter's
840 // latency at zero fractional delay.
841
842 memset( &Buf[ ReadPos ], 0,
843 (size_t) ( BufLen - flb ) * sizeof( Buf[ 0 ]));
844
845 if( IsWhole )
846 {
847 InPosFracW = InitFracPosW;
848 }
849 else
850 {
851 InPosFrac = InitFracPos;
852
853 #if !R8B_FASTTIMING
854 InCounter = 0;
855 InPosInt = 0;
856 InPosShift = InitFracPos * DstSampleRate / SrcSampleRate;
857 #endif // !R8B_FASTTIMING
858 }
859 }
860
861 virtual int process( double* ip, int l, double*& op0 )
862 {
863 R8BASSERT( l >= 0 );
864 R8BASSERT( ip != op0 || l == 0 || SrcSampleRate > DstSampleRate );
865
866 if( LatencyLeft != 0 )
867 {
868 if( LatencyLeft >= l )
869 {
870 LatencyLeft -= l;
871 return( 0 );
872 }
873
874 l -= LatencyLeft;
875 ip += LatencyLeft;
876 LatencyLeft = 0;
877 }
878
879 double* op = op0;
880
881 while( l > 0 )
882 {
883 // Copy new input samples to the ring buffer.
884
885 const int b = min( l, min( BufLen - WritePos, flb - BufLeft ));
886
887 double* const wp1 = Buf + WritePos;
888 memcpy( wp1, ip, (size_t) b * sizeof( wp1[ 0 ]));
889 const int ec = flo - WritePos;
890
891 if( ec > 0 )
892 {
893 memcpy( wp1 + BufLen, ip,
894 (size_t) min( b, ec ) * sizeof( wp1[ 0 ]));
895 }
896
897 ip += b;
898 WritePos = ( WritePos + b ) & BufLenMask;
899 l -= b;
900 BufLeft += b;
901
902 // Produce as many output samples as possible.
903
904 op = ( *this.*convfn )( op );
905 }
906
907 #if !R8B_FASTTIMING
908
909 if( !IsWhole && InCounter > 1000 )
910 {
911 // Reset the interpolation position counter to achieve a higher
912 // sample-timing precision.
913
914 InCounter = 0;
915 InPosInt = 0;
916 InPosShift = InPosFrac * DstSampleRate / SrcSampleRate;
917 }
918
919 #endif // !R8B_FASTTIMING
920
921 return( (int) ( op - op0 ));
922 }
923
924private:
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;
942 double InitFracPos;
944 int InitFracPosW;
946 int Latency;
947 double LatencyFrac;
949 int FilterLen;
950 int fll;
951 int fl2;
952 int flo;
953 int flb;
954 int InStep;
955 int OutStep;
957 int LatencyLeft;
958 int BufLeft;
959 int WritePos;
961 int ReadPos;
962 int InPosFracW;
965 double InPosFrac;
966
967#if R8B_FASTTIMING
968 double FracStep;
969#else // R8B_FASTTIMING
970 int InCounter;
971 int InPosInt;
972 double InPosShift;
973#endif // R8B_FASTTIMING
974
975 CDSPFracDelayFilterBank* FilterBank;
977 bool IsWhole;
978
979 typedef double*( CDSPFracInterpolator ::* CConvolveFn )( double* op );
981 CConvolveFn convfn;
982
990
991 template< int fltlen >
992 double* convolve0( double* op )
993 {
994 const CDSPFracDelayFilterBank& fb = *FilterBank;
995 const int istep = InStep;
996 const int ostep = OutStep;
997 int fpos = InPosFracW;
998 int rpos = ReadPos;
999 int bl = BufLeft - fl2;
1000
1001 while( bl > 0 )
1002 {
1003 const double* const ftp = &fb[ fpos ];
1004 const double* const rp = Buf + rpos;
1005 int i;
1006
1007 #if defined( R8B_SSE2 ) && !defined( __INTEL_COMPILER )
1008
1009 __m128d s = _mm_setzero_pd();
1010
1011 for( i = 0; i < fltlen; i += 2 )
1012 {
1013 const __m128d m = _mm_mul_pd( _mm_load_pd( ftp + i ),
1014 _mm_loadu_pd( rp + i ));
1015
1016 s = _mm_add_pd( s, m );
1017 }
1018
1019 _mm_storel_pd( op, _mm_add_pd( s, _mm_shuffle_pd( s, s, 1 )));
1020
1021 #elif defined( R8B_NEON )
1022
1023 float64x2_t s = vdupq_n_f64( 0.0 );
1024
1025 for( i = 0; i < fltlen; i += 2 )
1026 {
1027 s = vmlaq_f64( s, vld1q_f64( ftp + i ), vld1q_f64( rp + i ));
1028 }
1029
1030 *op = vaddvq_f64( s );
1031
1032 #else // SIMD
1033
1034 double s = 0.0;
1035
1036 for( i = 0; i < fltlen; i++ )
1037 {
1038 s += ftp[ i ] * rp[ i ];
1039 }
1040
1041 *op = s;
1042
1043 #endif // SIMD
1044
1045 op++;
1046
1047 fpos += istep;
1048 const int PosIncr = fpos / ostep;
1049 fpos -= PosIncr * ostep;
1050
1051 rpos = ( rpos + PosIncr ) & BufLenMask;
1052 bl -= PosIncr;
1053 }
1054
1055 BufLeft = bl + fl2;
1056 ReadPos = rpos;
1057 InPosFracW = fpos;
1058
1059 return( op );
1060 }
1061
1068
1069 double* convolve2( double* op )
1070 {
1071 const CDSPFracDelayFilterBank& fb = *FilterBank;
1072 const int fltlen = FilterLen;
1073 const double ssr = SrcSampleRate;
1074 const double dsr = DstSampleRate;
1075 double fpos = InPosFrac;
1076 int rpos = ReadPos;
1077 int bl = BufLeft - fl2;
1078
1079 while( bl > 0 )
1080 {
1081 double x = fpos * fb.getFilterFracs();
1082 const int fti = (int) x; // Function table index.
1083 x -= fti; // Coefficient for interpolation between adjacent
1084 // fractional delay filters.
1085 const double x2d = x * x;
1086 const double* ftp = &fb[ fti ];
1087 const double* const rp = Buf + rpos;
1088 int i;
1089
1090 #if defined( R8B_SSE2 ) && defined( R8B_SIMD_ISH )
1091
1092 const __m128d x1 = _mm_set1_pd( x );
1093 const __m128d x2 = _mm_set1_pd( x2d );
1094 __m128d s = _mm_setzero_pd();
1095
1096 for( i = 0; i < fltlen; i += 2 )
1097 {
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 );
1103 ftp += 6;
1104
1105 const __m128d rpi = _mm_loadu_pd( rp + i );
1106 const __m128d xxs = _mm_add_pd( ftp0, _mm_add_pd( xx1, xx2 ));
1107
1108 s = _mm_add_pd( s, _mm_mul_pd( rpi, xxs ));
1109 }
1110
1111 _mm_storel_pd( op, _mm_add_pd( s, _mm_shuffle_pd( s, s, 1 )));
1112
1113 #elif defined( R8B_NEON ) && defined( R8B_SIMD_ISH )
1114
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 );
1118
1119 for( i = 0; i < fltlen; i += 2 )
1120 {
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 );
1126 ftp += 6;
1127
1128 const float64x2_t rpi = vld1q_f64( rp + i );
1129 const float64x2_t xxs = vaddq_f64( ftp0,
1130 vaddq_f64( xx1, xx2 ));
1131
1132 s = vmlaq_f64( s, rpi, xxs );
1133 }
1134
1135 *op = vaddvq_f64( s );
1136
1137 #else // SIMD
1138
1139 double s = 0.0;
1140
1141 for( i = 0; i < fltlen; i++ )
1142 {
1143 s += ( ftp[ 0 ] + ftp[ 1 ] * x + ftp[ 2 ] * x2d ) * rp[ i ];
1144 ftp += 3;
1145 }
1146
1147 *op = s;
1148
1149 #endif // SIMD
1150
1151 op++;
1152
1153 #if R8B_FASTTIMING
1154
1155 fpos += FracStep;
1156 const int PosIncr = (int) fpos;
1157 fpos -= PosIncr;
1158
1159 #else // R8B_FASTTIMING
1160
1161 InCounter++;
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;
1167
1168 #endif // R8B_FASTTIMING
1169
1170 rpos = ( rpos + PosIncr ) & BufLenMask;
1171 bl -= PosIncr;
1172 }
1173
1174 BufLeft = bl + fl2;
1175 ReadPos = rpos;
1176 InPosFrac = fpos;
1177
1178 return( op );
1179 }
1180};
1181
1182// ---------------------------------------------------------------------------
1183
1184} // namespace r8b
1185
1186#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: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