r8brain-free-src
High-quality pro audio sample rate converter library
Loading...
Searching...
No Matches
r8bbase.h
Go to the documentation of this file.
1//$ nobt
2
60#ifndef R8BBASE_INCLUDED
61#define R8BBASE_INCLUDED
62
63#include <stdlib.h>
64#include <stdint.h>
65#include <string.h>
66#include <math.h>
67#include "r8bconf.h"
68
69#if defined( _WIN32 )
70 #include <windows.h>
71#else // defined( _WIN32 )
72 #include <pthread.h>
73#endif // defined( _WIN32 )
74
75#if defined( __SSE4_2__ ) || defined( __SSE4_1__ ) || \
76 defined( __SSSE3__ ) || defined( __SSE3__ ) || defined( __SSE2__ ) || \
77 defined( __x86_64__ ) || defined( __amd64 ) || defined( _M_X64 ) || \
78 defined( _M_AMD64 ) || ( defined( _M_IX86_FP ) && _M_IX86_FP == 2 )
79
80 #if defined( _MSC_VER )
81 #include <intrin.h>
82 #else // defined( _MSC_VER )
83 #include <emmintrin.h>
84 #endif // defined( _MSC_VER )
85
86 #define R8B_SSE2
87 #define R8B_SIMD_ISH
88
89#elif defined( __aarch64__ ) || defined( __arm64 )
90
91 #include <arm_neon.h>
92
93 #define R8B_NEON
94
95 #if !defined( __APPLE__ )
96 #define R8B_SIMD_ISH // Shuffled interpolation is inefficient on M1.
97 #endif // !defined( __APPLE__ )
98
99#endif // AArch64
100
107namespace r8b {
108
113#define R8B_VERSION "6.5"
114
119#define R8B_PI 3.14159265358979324
120
126#define R8B_2PI 6.28318530717958648
127
133#define R8B_3PI 9.42477796076937972
134
140#define R8B_PId2 1.57079632679489662
141
154#define R8BNOCTOR( ClassName ) \
155 private: \
156 ClassName( const ClassName& ) { } \
157 ClassName& operator = ( const ClassName& ) { return( *this ); }
158
167{
168public:
174 void* operator new( const size_t, void* const p )
175 {
176 return( p );
177 }
178
184 void* operator new( const size_t n )
185 {
186 return( :: malloc( n ));
187 }
188
194 void* operator new[]( const size_t n )
195 {
196 return( :: malloc( n ));
197 }
198
205 void operator delete( void* const p )
206 {
207 :: free( p );
208 }
209
216 void operator delete[]( void* const p )
217 {
218 :: free( p );
219 }
220};
221
229{
230public:
238 static void* allocmem( const size_t Size )
239 {
240 return( :: malloc( Size ));
241 }
242
251 static void* reallocmem( void* const p, const size_t Size )
252 {
253 return( :: realloc( p, Size ));
254 }
255
262 static void freemem( void* const p )
263 {
264 :: free( p );
265 }
266};
267
278template< typename T >
279inline T* alignptr( T* const ptr, const uintptr_t align )
280{
281 return( (T*) (( (uintptr_t) ptr + align - 1 ) & ~( align - 1 )));
282}
283
302template< typename T >
304{
306
307public:
309 : Data0( NULL )
310 , Data( NULL )
311 {
312 }
313
321 CFixedBuffer( const int Capacity )
322 {
323 R8BASSERT( Capacity > 0 || Capacity == 0 );
324
325 Data0 = allocmem( Capacity * sizeof( T ) + Alignment );
326 Data = (T*) alignptr( Data0, Alignment );
327
328 R8BASSERT( Data0 != NULL || Capacity == 0 );
329 }
330
332 {
333 freemem( Data0 );
334 }
335
343 void alloc( const int Capacity )
344 {
345 R8BASSERT( Capacity > 0 || Capacity == 0 );
346
347 freemem( Data0 );
348 Data0 = allocmem( Capacity * sizeof( T ) + Alignment );
349 Data = (T*) alignptr( Data0, Alignment );
350
351 R8BASSERT( Data0 != NULL || Capacity == 0 );
352 }
353
363 void realloc( const int PrevCapacity, const int NewCapacity )
364 {
365 R8BASSERT( PrevCapacity >= 0 );
366 R8BASSERT( NewCapacity >= 0 );
367
368 void* const NewData0 = allocmem( NewCapacity * sizeof( T ) +
369 Alignment );
370
371 T* const NewData = (T*) alignptr( NewData0, Alignment );
372 const size_t CopySize = ( PrevCapacity > NewCapacity ?
373 NewCapacity : PrevCapacity ) * sizeof( T );
374
375 if( CopySize > 0 )
376 {
377 memcpy( NewData, Data, CopySize );
378 }
379
380 freemem( Data0 );
381 Data0 = NewData0;
382 Data = NewData;
383
384 R8BASSERT( Data0 != NULL || NewCapacity == 0 );
385 }
386
391 void free()
392 {
393 freemem( Data0 );
394 Data0 = NULL;
395 Data = NULL;
396 }
397
403 operator T* () const
404 {
405 return( Data );
406 }
407
408private:
409 static const size_t Alignment = 64;
411 void* Data0;
412 T* Data;
413};
414
426template< typename T >
428{
430
431public:
432 CPtrKeeper()
433 : Object( NULL )
434 {
435 }
436
444 template< typename T2 >
445 CPtrKeeper( T2 const aObject )
446 : Object( aObject )
447 {
448 }
449
451 {
452 delete Object;
453 }
454
463 template< typename T2 >
464 void operator = ( T2 const aObject )
465 {
466 reset();
467 Object = aObject;
468 }
469
474 T operator -> () const
475 {
476 return( Object );
477 }
478
483 operator T () const
484 {
485 return( Object );
486 }
487
492 void reset()
493 {
494 T DelObj = Object;
495 Object = NULL;
496 delete DelObj;
497 }
498
505 {
506 T ResObject = Object;
507 Object = NULL;
508 return( ResObject );
509 }
510
511private:
512 T Object;
513};
514
526{
528
529public:
531 {
532 #if defined( _WIN32 )
533 InitializeCriticalSectionAndSpinCount( &CritSec, 2000 );
534 #else // defined( _WIN32 )
535 pthread_mutexattr_t MutexAttrs;
536 pthread_mutexattr_init( &MutexAttrs );
537 pthread_mutexattr_settype( &MutexAttrs, PTHREAD_MUTEX_RECURSIVE );
538 pthread_mutex_init( &Mutex, &MutexAttrs );
539 pthread_mutexattr_destroy( &MutexAttrs );
540 #endif // defined( _WIN32 )
541 }
542
544 {
545 #if defined( _WIN32 )
546 DeleteCriticalSection( &CritSec );
547 #else // defined( _WIN32 )
548 pthread_mutex_destroy( &Mutex );
549 #endif // defined( _WIN32 )
550 }
551
557 void acquire()
558 {
559 #if defined( _WIN32 )
560 EnterCriticalSection( &CritSec );
561 #else // defined( _WIN32 )
562 pthread_mutex_lock( &Mutex );
563 #endif // defined( _WIN32 )
564 }
565
571 void release()
572 {
573 #if defined( _WIN32 )
574 LeaveCriticalSection( &CritSec );
575 #else // defined( _WIN32 )
576 pthread_mutex_unlock( &Mutex );
577 #endif // defined( _WIN32 )
578 }
579
580private:
581 #if defined( _WIN32 )
582 CRITICAL_SECTION CritSec;
584 #else // defined( _WIN32 )
585 pthread_mutex_t Mutex;
586 #endif // defined( _WIN32 )
587};
588
600{
602
603public:
605 : SyncObj( NULL )
606 {
607 }
608
614 CSyncKeeper( CSyncObject* const aSyncObj )
615 : SyncObj( aSyncObj )
616 {
617 if( SyncObj != NULL )
618 {
619 SyncObj -> acquire();
620 }
621 }
622
629 : SyncObj( &aSyncObj )
630 {
631 SyncObj -> acquire();
632 }
633
635 {
636 if( SyncObj != NULL )
637 {
638 SyncObj -> release();
639 }
640 }
641
642private:
643 CSyncObject* SyncObj;
644};
645
660#define R8BSYNC( SyncObject ) R8BSYNC_( SyncObject, __LINE__ )
661#define R8BSYNC_( SyncObject, id ) R8BSYNC__( SyncObject, id )
662#define R8BSYNC__( SyncObject, id ) CSyncKeeper SyncKeeper##id( SyncObject )
663
671{
672public:
673 CSineGen()
674 {
675 }
676
685 CSineGen( const double si, const double ph )
686 : svalue1( sin( ph ))
687 , svalue2( sin( ph - si ))
688 , sincr( 2.0 * cos( si ))
689 {
690 }
691
701 CSineGen( const double si, const double ph, const double g )
702 : svalue1( sin( ph ) * g )
703 , svalue2( sin( ph - si ) * g )
704 , sincr( 2.0 * cos( si ))
705 {
706 }
707
716 void init( const double si, const double ph )
717 {
718 svalue1 = sin( ph );
719 svalue2 = sin( ph - si );
720 sincr = 2.0 * cos( si );
721 }
722
732 void init( const double si, const double ph, const double g )
733 {
734 svalue1 = sin( ph ) * g;
735 svalue2 = sin( ph - si ) * g;
736 sincr = 2.0 * cos( si );
737 }
738
743 double generate()
744 {
745 const double res = svalue1;
746
747 svalue1 = sincr * res - svalue2;
748 svalue2 = res;
749
750 return( res );
751 }
752
753private:
754 double svalue1;
755 double svalue2;
756 double sincr;
757};
758
766inline int getBitOccupancy( const int v )
767{
768 static const uint8_t OccupancyTable[] =
769 {
770 1, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
771 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
772 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
773 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
774 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
775 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
776 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
777 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
778 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
779 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
780 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
781 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
782 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
783 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
784 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
785 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8
786 };
787
788 const int tt = v >> 16;
789
790 if( tt != 0 )
791 {
792 const int t = v >> 24;
793
794 return( t != 0 ? 24 + OccupancyTable[ t & 0xFF ] :
795 16 + OccupancyTable[ tt ]);
796 }
797 else
798 {
799 const int t = v >> 8;
800
801 return( t != 0 ? 8 + OccupancyTable[ t ] : OccupancyTable[ v ]);
802 }
803}
804
817inline void calcFIRFilterResponse( const double* flt, int fltlen,
818 const double th, double& re0, double& im0, const int fltlat = 0 )
819{
820 const double sincr = 2.0 * cos( th );
821 double cvalue1;
822 double svalue1;
823
824 if( fltlat == 0 )
825 {
826 cvalue1 = 1.0;
827 svalue1 = 0.0;
828 }
829 else
830 {
831 cvalue1 = cos( -fltlat * th );
832 svalue1 = sin( -fltlat * th );
833 }
834
835 double cvalue2 = cos( -( fltlat + 1 ) * th );
836 double svalue2 = sin( -( fltlat + 1 ) * th );
837
838 double re = 0.0;
839 double im = 0.0;
840
841 while( fltlen > 0 )
842 {
843 re += cvalue1 * flt[ 0 ];
844 im += svalue1 * flt[ 0 ];
845 flt++;
846 fltlen--;
847
848 double tmp = cvalue1;
849 cvalue1 = sincr * cvalue1 - cvalue2;
850 cvalue2 = tmp;
851
852 tmp = svalue1;
853 svalue1 = sincr * svalue1 - svalue2;
854 svalue2 = tmp;
855 }
856
857 re0 = re;
858 im0 = im;
859}
860
872inline double calcFIRFilterGroupDelay( const double* const flt,
873 const int fltlen, const double th )
874{
875 const int Count = 2;
876 const double thd2 = 1e-9;
877 double ths[ Count ] = { th - thd2, th + thd2 }; // Side-band frequencies.
878
879 if( ths[ 0 ] < 0.0 )
880 {
881 ths[ 0 ] = 0.0;
882 }
883
884 if( ths[ 1 ] > R8B_PI )
885 {
886 ths[ 1 ] = R8B_PI;
887 }
888
889 double ph1[ Count ];
890 int i;
891
892 for( i = 0; i < Count; i++ )
893 {
894 double re1;
895 double im1;
896
897 calcFIRFilterResponse( flt, fltlen, ths[ i ], re1, im1 );
898 ph1[ i ] = atan2( im1, re1 );
899 }
900
901 if( fabs( ph1[ 1 ] - ph1[ 0 ]) > R8B_PI )
902 {
903 if( ph1[ 1 ] > ph1[ 0 ])
904 {
905 ph1[ 1 ] -= R8B_2PI;
906 }
907 else
908 {
909 ph1[ 1 ] += R8B_2PI;
910 }
911 }
912
913 const double thd = ths[ 1 ] - ths[ 0 ];
914
915 return(( ph1[ 1 ] - ph1[ 0 ]) / thd );
916}
917
928inline void normalizeFIRFilter( double* const p, const int l,
929 const double DCGain, const int pstep = 1 )
930{
931 R8BASSERT( l > 0 );
932 R8BASSERT( pstep != 0 );
933
934 double s = 0.0;
935 double* pp = p;
936 int i = l;
937
938 while( i > 0 )
939 {
940 s += *pp;
941 pp += pstep;
942 i--;
943 }
944
945 s = DCGain / s;
946 pp = p;
947 i = l;
948
949 while( i > 0 )
950 {
951 *pp *= s;
952 pp += pstep;
953 i--;
954 }
955}
956
972inline void calcSpline3p8Coeffs( double* const c, const double xm3,
973 const double xm2, const double xm1, const double x0, const double x1,
974 const double x2, const double x3, const double x4 )
975{
976 c[ 0 ] = x0;
977 c[ 1 ] = ( 61.0 * ( x1 - xm1 ) + 16.0 * ( xm2 - x2 ) +
978 3.0 * ( x3 - xm3 )) * 1.31578947368421052e-2;
979
980 c[ 2 ] = ( 106.0 * ( xm1 + x1 ) + 10.0 * x3 + 6.0 * xm3 - 3.0 * x4 -
981 29.0 * ( xm2 + x2 ) - 167.0 * x0 ) * 1.31578947368421052e-2;
982
983 c[ 3 ] = ( 91.0 * ( x0 - x1 ) + 45.0 * ( x2 - xm1 ) +
984 13.0 * ( xm2 - x3 ) + 3.0 * ( x4 - xm3 )) * 1.31578947368421052e-2;
985}
986
1004inline void calcSpline2p8Coeffs( double* const c, const double xm3,
1005 const double xm2, const double xm1, const double x0, const double x1,
1006 const double x2, const double x3, const double x4 )
1007{
1008 c[ 0 ] = x0;
1009 c[ 1 ] = ( 61.0 * ( x1 - xm1 ) + 16.0 * ( xm2 - x2 ) +
1010 3.0 * ( x3 - xm3 )) * 1.31578947368421052e-2;
1011
1012 c[ 2 ] = ( 106.0 * ( xm1 + x1 ) + 10.0 * x3 + 6.0 * xm3 - 3.0 * x4 -
1013 29.0 * ( xm2 + x2 ) - 167.0 * x0 ) * 1.31578947368421052e-2;
1014}
1015
1025inline void calcSpline3p4Coeffs( double* const c, const double* const y )
1026{
1027 c[ 0 ] = y[ 1 ];
1028 c[ 1 ] = 0.5 * ( y[ 2 ] - y[ 0 ]);
1029 c[ 2 ] = y[ 0 ] - 2.5 * y[ 1 ] + y[ 2 ] + y[ 2 ] - 0.5 * y[ 3 ];
1030 c[ 3 ] = 0.5 * ( y[ 3 ] - y[ 0 ] ) + 1.5 * ( y[ 1 ] - y[ 2 ]);
1031}
1032
1042inline void calcSpline3p6Coeffs( double* const c, const double* const y )
1043{
1044 c[ 0 ] = y[ 2 ];
1045 c[ 1 ] = ( 11.0 * ( y[ 3 ] - y[ 1 ]) + 2.0 * ( y[ 0 ] - y[ 4 ])) / 14.0;
1046 c[ 2 ] = ( 20.0 * ( y[ 1 ] + y[ 3 ]) + 2.0 * y[ 5 ] - 4.0 * y[ 0 ] -
1047 7.0 * y[ 4 ] - 31.0 * y[ 2 ]) / 14.0;
1048
1049 c[ 3 ] = ( 17.0 * ( y[ 2 ] - y[ 3 ]) + 9.0 * ( y[ 4 ] - y[ 1 ]) +
1050 2.0 * ( y[ 0 ] - y[ 5 ])) / 14.0;
1051}
1052
1053#if !defined( min )
1054
1062template< typename T >
1063inline T min( const T& v1, const T& v2 )
1064{
1065 return( v1 < v2 ? v1 : v2 );
1066}
1067
1068#endif // min
1069
1070#if !defined( max )
1071
1079template< typename T >
1080inline T max( const T& v1, const T& v2 )
1081{
1082 return( v1 > v2 ? v1 : v2 );
1083}
1084
1085#endif // max
1086
1097inline double clampr( const double Value, const double minv,
1098 const double maxv )
1099{
1100 if( Value < minv )
1101 {
1102 return( minv );
1103 }
1104 else
1105 if( Value > maxv )
1106 {
1107 return( maxv );
1108 }
1109 else
1110 {
1111 return( Value );
1112 }
1113}
1114
1120inline double sqr( const double x )
1121{
1122 return( x * x );
1123}
1124
1132inline double pow_a( const double v, const double p )
1133{
1134 return( exp( p * log( fabs( v ) + 1e-300 )));
1135}
1136
1142inline double gauss( const double v )
1143{
1144 return( exp( -( v * v )));
1145}
1146
1152inline double asinh( const double v )
1153{
1154 return( log( v + sqrt( v * v + 1.0 )));
1155}
1156
1164inline double besselI0( const double x )
1165{
1166 const double ax = fabs( x );
1167 double y;
1168
1169 if( ax < 3.75 )
1170 {
1171 y = x / 3.75;
1172 y *= y;
1173
1174 return( 1.0 + y * ( 3.5156229 + y * ( 3.0899424 + y * ( 1.2067492 +
1175 y * ( 0.2659732 + y * ( 0.360768e-1 + y * 0.45813e-2 ))))));
1176 }
1177
1178 y = 3.75 / ax;
1179
1180 return( exp( ax ) / sqrt( ax ) * ( 0.39894228 + y * ( 0.1328592e-1 +
1181 y * ( 0.225319e-2 + y * ( -0.157565e-2 + y * ( 0.916281e-2 +
1182 y * ( -0.2057706e-1 + y * ( 0.2635537e-1 + y * ( -0.1647633e-1 +
1183 y * 0.392377e-2 )))))))));
1184}
1185
1186} // namespace r8b
1187
1188#endif // R8BBASE_INCLUDED
#define R8B_PI
Definition: r8bbase.h:119
#define R8B_2PI
Definition: r8bbase.h:126
#define R8BNOCTOR(ClassName)
Definition: r8bbase.h:154
The "configuration" inclusion file you can modify.
#define R8BASSERT(e)
Definition: r8bconf.h:27
#define R8B_MEMALLOCCLASS
Definition: r8bconf.h:63
The "r8brain-free-src" library namespace.
Definition: CDSPBlockConvolver.h:21
T * alignptr(T *const ptr, const uintptr_t align)
Definition: r8bbase.h:279
double calcFIRFilterGroupDelay(const double *const flt, const int fltlen, const double th)
Definition: r8bbase.h:872
void calcSpline3p4Coeffs(double *const c, const double *const y)
Definition: r8bbase.h:1025
double pow_a(const double v, const double p)
Definition: r8bbase.h:1132
void calcFIRFilterResponse(const double *flt, int fltlen, const double th, double &re0, double &im0, const int fltlat=0)
Definition: r8bbase.h:817
void calcSpline3p6Coeffs(double *const c, const double *const y)
Definition: r8bbase.h:1042
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
int getBitOccupancy(const int v)
Definition: r8bbase.h:766
double asinh(const double v)
Definition: r8bbase.h:1152
T max(const T &v1, const T &v2)
Definition: r8bbase.h:1080
double clampr(const double Value, const double minv, const double maxv)
Definition: r8bbase.h:1097
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
double gauss(const double v)
Definition: r8bbase.h:1142
double besselI0(const double x)
Definition: r8bbase.h:1164
void normalizeFIRFilter(double *const p, const int l, const double DCGain, const int pstep=1)
Definition: r8bbase.h:928
double sqr(const double x)
Definition: r8bbase.h:1120
The default base class for objects created on heap.
Definition: r8bbase.h:167
The default base class for objects that allocate blocks of memory.
Definition: r8bbase.h:229
static void * reallocmem(void *const p, const size_t Size)
Definition: r8bbase.h:251
static void * allocmem(const size_t Size)
Definition: r8bbase.h:238
static void freemem(void *const p)
Definition: r8bbase.h:262
Templated memory buffer class for element buffers of fixed capacity.
Definition: r8bbase.h:304
void alloc(const int Capacity)
Definition: r8bbase.h:343
void free()
Definition: r8bbase.h:391
CFixedBuffer(const int Capacity)
Definition: r8bbase.h:321
void realloc(const int PrevCapacity, const int NewCapacity)
Definition: r8bbase.h:363
Pointer-to-object "keeper" class with automatic deletion.
Definition: r8bbase.h:428
void operator=(T2 const aObject)
Definition: r8bbase.h:464
CPtrKeeper(T2 const aObject)
Definition: r8bbase.h:445
void reset()
Definition: r8bbase.h:492
T operator->() const
Definition: r8bbase.h:474
T unkeep()
Definition: r8bbase.h:504
Multi-threaded synchronization object class.
Definition: r8bbase.h:526
void acquire()
Definition: r8bbase.h:557
void release()
Definition: r8bbase.h:571
A "keeper" class for CSyncObject-based synchronization.
Definition: r8bbase.h:600
CSyncKeeper(CSyncObject &aSyncObj)
Definition: r8bbase.h:628
CSyncKeeper(CSyncObject *const aSyncObj)
Definition: r8bbase.h:614
Sine signal generator class.
Definition: r8bbase.h:671
CSineGen(const double si, const double ph)
Definition: r8bbase.h:685
CSineGen(const double si, const double ph, const double g)
Definition: r8bbase.h:701
void init(const double si, const double ph, const double g)
Definition: r8bbase.h:732
void init(const double si, const double ph)
Definition: r8bbase.h:716
double generate()
Definition: r8bbase.h:743