r8brain-free-src
High-quality pro audio sample rate converter library
Loading...
Searching...
No Matches
CDSPSincFilterGen.h
Go to the documentation of this file.
1//$ nobt
2//$ nocpp
3
16#ifndef R8B_CDSPSINCFILTERGEN_INCLUDED
17#define R8B_CDSPSINCFILTERGEN_INCLUDED
18
19#include "r8bbase.h"
20
21namespace r8b {
22
32{
33public:
34 double Len2;
37 double Len2i;
42 int fl2;
45
46 union
47 {
48 struct
49 {
50 double Freq1;
52 double Freq2;
56 };
57
58 struct
59 {
60 double FracDelay;
66 };
67 };
68
74 {
75 wftCosine,
77 wftKaiser,
81 };
82
83 typedef double( CDSPSincFilterGen :: *CWindowFunc )();
85
100 const double* const Params = NULL, const bool UsePower = false )
101 {
102 R8BASSERT( Len2 >= 2.0 );
103
104 fl2 = (int) floor( Len2 );
105 KernelLen = fl2 + fl2 + 1;
106
107 setWindow( WinType, Params, UsePower, true );
108 }
109
125 const double* const Params = NULL, const bool UsePower = false )
126 {
127 R8BASSERT( Len2 >= 2.0 );
128
129 fl2 = (int) floor( Len2 );
130 KernelLen = fl2 + fl2 + 1;
131
132 setWindow( WinType, Params, UsePower, true );
133 }
134
150 const double* const Params = NULL, const bool UsePower = false )
151 {
152 R8BASSERT( Len2 >= 2.0 );
153
154 fl2 = (int) floor( Len2 );
155 KernelLen = fl2 + fl2 + 1;
156
157 setWindow( WinType, Params, UsePower, true );
158 }
159
176 const double* const Params = NULL, const bool UsePower = false )
177 {
178 R8BASSERT( Len2 >= 2.0 );
179
180 fl2 = (int) ceil( Len2 );
181 KernelLen = fl2 + fl2;
182
183 setWindow( WinType, Params, UsePower, false, FracDelay );
184 }
185
191 {
192 return( 0.5 + 0.5 * w1.generate() );
193 }
194
200 {
201 return( 0.54 + 0.46 * w1.generate() );
202 }
203
209 {
210 return( 0.42 + 0.5 * w1.generate() + 0.08 * w2.generate() );
211 }
212
218 {
219 return( 0.355768 + 0.487396 * w1.generate() +
220 0.144232 * w2.generate() + 0.012604 * w3.generate() );
221 }
222
228 {
229 return( 0.3635819 + 0.4891775 * w1.generate() +
230 0.1365995 * w2.generate() + 0.0106411 * w3.generate() );
231 }
232
238 {
239 const double n = 1.0 - sqr( wn * Len2i + KaiserLen2Frac );
240 wn++;
241
242 if( n <= 0.0 )
243 {
244 return( 0.0 );
245 }
246
247 return( besselI0( KaiserBeta * sqrt( n )) * KaiserMul );
248 }
249
255 {
256 const double f = exp( -0.5 * sqr( wn * GaussianSigmaI +
258
259 wn++;
260
261 return( f );
262 }
263
271 void generateWindow( double* op,
272 CWindowFunc wfunc = &CDSPSincFilterGen :: calcWindowBlackman )
273 {
274 op += fl2;
275 double* op2 = op;
276
277 int l = fl2;
278
279 if( Power < 0.0 )
280 {
281 *op = ( *this.*wfunc )();
282
283 while( l > 0 )
284 {
285 const double v = ( *this.*wfunc )();
286
287 op++;
288 op2--;
289 *op = v;
290 *op2 = v;
291 l--;
292 }
293 }
294 else
295 {
296 *op = pow_a(( *this.*wfunc )(), Power );
297
298 while( l > 0 )
299 {
300 const double v = pow_a(( *this.*wfunc )(), Power );
301
302 op++;
303 op2--;
304 *op = v;
305 *op2 = v;
306 l--;
307 }
308 }
309 }
310
319 void generateBand( double* op,
320 CWindowFunc wfunc = &CDSPSincFilterGen :: calcWindowBlackman )
321 {
322 CSineGen f2( Freq2, 0.0, 1.0 / R8B_PI );
323 f2.generate();
324
325 op += fl2;
326 double* op2 = op;
327 const double pw = Power;
328 int t = 1;
329
330 if( Freq1 < 2.3e-13 )
331 {
332 if( pw < 0.0 )
333 {
334 *op = Freq2 * ( *this.*wfunc )() / R8B_PI;
335
336 while( t <= fl2 )
337 {
338 const double v = f2.generate() * ( *this.*wfunc )() / t;
339 op++;
340 op2--;
341 *op = v;
342 *op2 = v;
343 t++;
344 }
345 }
346 else
347 {
348 *op = Freq2 * pow_a(( *this.*wfunc )(), pw ) / R8B_PI;
349
350 while( t <= fl2 )
351 {
352 const double v = f2.generate() *
353 pow_a(( *this.*wfunc )(), pw ) / t;
354
355 op++;
356 op2--;
357 *op = v;
358 *op2 = v;
359 t++;
360 }
361 }
362 }
363 else
364 {
365 CSineGen f1( Freq1, 0.0, 1.0 / R8B_PI );
366 f1.generate();
367
368 if( pw < 0.0 )
369 {
370 *op = ( Freq2 - Freq1 ) * ( *this.*wfunc )() / R8B_PI;
371
372 while( t <= fl2 )
373 {
374 const double v = ( f2.generate() - f1.generate() ) *
375 ( *this.*wfunc )() / t;
376
377 op++;
378 op2--;
379 *op = v;
380 *op2 = v;
381 t++;
382 }
383 }
384 else
385 {
386 *op = ( Freq2 - Freq1 ) *
387 pow_a(( *this.*wfunc )(), pw ) / R8B_PI;
388
389 while( t <= fl2 )
390 {
391 const double v = ( f2.generate() - f1.generate() ) *
392 pow_a(( *this.*wfunc )(), pw ) / t;
393
394 op++;
395 op2--;
396 *op = v;
397 *op2 = v;
398 t++;
399 }
400 }
401 }
402 }
403
411 void generateHilbert( double* op,
412 CWindowFunc wfunc = &CDSPSincFilterGen :: calcWindowBlackman )
413 {
414 static const double fvalues[ 2 ] = { 0.0, 2.0 / R8B_PI };
415 op += fl2;
416 double* op2 = op;
417
418 ( *this.*wfunc )();
419 *op = 0.0;
420
421 int t = 1;
422
423 if( Power < 0.0 )
424 {
425 while( t <= fl2 )
426 {
427 const double v = fvalues[ t & 1 ] * ( *this.*wfunc )() / t;
428 op++;
429 op2--;
430 *op = v;
431 *op2 = -v;
432 t++;
433 }
434 }
435 else
436 {
437 while( t <= fl2 )
438 {
439 const double v = fvalues[ t & 1 ] *
440 pow_a(( *this.*wfunc )(), Power ) / t;
441
442 op++;
443 op2--;
444 *op = v;
445 *op2 = -v;
446 t++;
447 }
448 }
449 }
450
459 void generateFrac( double* op,
460 CWindowFunc wfunc = &CDSPSincFilterGen :: calcWindowBlackman,
461 const int opinc = 1 )
462 {
463 R8BASSERT( opinc != 0 );
464
465 const double pw = Power;
466 const double fd = FracDelay;
467 int t = -fl2;
468
469 if( t + fd < -Len2 )
470 {
471 ( *this.*wfunc )();
472 *op = 0.0;
473 op += opinc;
474 t++;
475 }
476
477 double f = sin( fd * R8B_PI ) / R8B_PI;
478
479 if(( t & 1 ) != 0 )
480 {
481 f = -f;
482 }
483
484 int IsZeroX = ( fabs( fd - 1.0 ) < 2.3e-13 );
485 int mt = 0 - IsZeroX;
486 IsZeroX = ( IsZeroX || fabs( fd ) < 2.3e-13 );
487
488 if( pw < 0.0 )
489 {
490 while( t < mt )
491 {
492 *op = f * ( *this.*wfunc )() / ( t + fd );
493 op += opinc;
494 t++;
495 f = -f;
496 }
497
498 if( IsZeroX ) // t+FracDelay==0
499 {
500 *op = ( *this.*wfunc )();
501 }
502 else
503 {
504 *op = f * ( *this.*wfunc )() / fd; // t==0
505 }
506
507 mt = fl2 - 2;
508
509 while( t < mt )
510 {
511 op += opinc;
512 t++;
513 f = -f;
514 *op = f * ( *this.*wfunc )() / ( t + fd );
515 }
516
517 op += opinc;
518 t++;
519 f = -f;
520 const double ut = t + fd;
521 *op = ( ut > Len2 ? 0.0 : f * ( *this.*wfunc )() / ut );
522 }
523 else
524 {
525 while( t < mt )
526 {
527 *op = f * pow_a(( *this.*wfunc )(), pw ) / ( t + fd );
528 op += opinc;
529 t++;
530 f = -f;
531 }
532
533 if( IsZeroX ) // t+FracDelay==0
534 {
535 *op = pow_a(( *this.*wfunc )(), pw );
536 }
537 else
538 {
539 *op = f * pow_a(( *this.*wfunc )(), pw ) / fd; // t==0
540 }
541
542 mt = fl2 - 2;
543
544 while( t < mt )
545 {
546 op += opinc;
547 t++;
548 f = -f;
549 *op = f * pow_a(( *this.*wfunc )(), pw ) / ( t + fd );
550 }
551
552 op += opinc;
553 t++;
554 f = -f;
555 const double ut = t + FracDelay;
556 *op = ( ut > Len2 ? 0.0 :
557 f * pow_a(( *this.*wfunc )(), pw ) / ut );
558 }
559 }
560
561private:
562 double Power;
564 CSineGen w1;
565 CSineGen w2;
566 CSineGen w3;
567
568 union
569 {
570 struct
571 {
572 double KaiserBeta;
574 double KaiserMul;
576 };
577
578 struct
579 {
583 };
584 };
585
586 int wn;
588
601 void setWindowKaiser( const double* Params, const bool UsePower,
602 const bool IsCentered )
603 {
604 wn = ( IsCentered ? 0 : -fl2 );
605
606 if( Params == NULL )
607 {
608 KaiserBeta = 9.5945013206755156;
609 Power = ( UsePower ? 1.9718457932433306 : -1.0 );
610 }
611 else
612 {
613 KaiserBeta = clampr( Params[ 0 ], 1.0, 350.0 );
614 Power = ( UsePower ? fabs( Params[ 1 ]) : -1.0 );
615 }
616
617 KaiserMul = 1.0 / besselI0( KaiserBeta );
618 Len2i = 1.0 / Len2;
620 }
621
635 void setWindowGaussian( const double* Params, const bool UsePower,
636 const bool IsCentered )
637 {
638 wn = ( IsCentered ? 0 : -fl2 );
639
640 if( Params == NULL )
641 {
642 GaussianSigmaI = 1.0;
643 Power = -1.0;
644 }
645 else
646 {
647 GaussianSigmaI = clampr( fabs( Params[ 0 ]), 1e-1, 100.0 );
648 Power = ( UsePower ? fabs( Params[ 1 ]) : -1.0 );
649 }
650
654 }
655
672 void setWindow( const EWindowFunctionType WinType,
673 const double* const Params, const bool UsePower,
674 const bool IsCentered, const double UseFracDelay = 0.0 )
675 {
676 FracDelay = UseFracDelay;
677
678 if( WinType == wftCosine )
679 {
680 if( IsCentered )
681 {
682 w1.init( R8B_PI / Len2, R8B_PId2 );
683 w2.init( R8B_2PI / Len2, R8B_PId2 );
684 w3.init( R8B_3PI / Len2, R8B_PId2 );
685 }
686 else
687 {
688 const double step1 = R8B_PI / Len2;
689 w1.init( step1, R8B_PId2 - step1 * fl2 + step1 * FracDelay );
690
691 const double step2 = R8B_2PI / Len2;
692 w2.init( step2, R8B_PId2 - step2 * fl2 + step2 * FracDelay );
693
694 const double step3 = R8B_3PI / Len2;
695 w3.init( step3, R8B_PId2 - step3 * fl2 + step3 * FracDelay );
696 }
697
698 Power = ( UsePower && Params != NULL ? Params[ 0 ] : -1.0 );
699 }
700 else
701 if( WinType == wftKaiser )
702 {
703 setWindowKaiser( Params, UsePower, IsCentered );
704 }
705 else
706 if( WinType == wftGaussian )
707 {
708 setWindowGaussian( Params, UsePower, IsCentered );
709 }
710 }
711};
712
713} // namespace r8b
714
715#endif // R8B_CDSPSINCFILTERGEN_INCLUDED
The "base" inclusion file with basic classes and functions.
#define R8B_PI
Definition: r8bbase.h:119
#define R8B_3PI
Definition: r8bbase.h:133
#define R8B_2PI
Definition: r8bbase.h:126
#define R8B_PId2
Definition: r8bbase.h:140
#define R8BASSERT(e)
Definition: r8bconf.h:27
The "r8brain-free-src" library namespace.
Definition: CDSPBlockConvolver.h:21
double pow_a(const double v, const double p)
Definition: r8bbase.h:1132
double clampr(const double Value, const double minv, const double maxv)
Definition: r8bbase.h:1097
double besselI0(const double x)
Definition: r8bbase.h:1164
double sqr(const double x)
Definition: r8bbase.h:1120
Sinc function-based FIR filter generator class.
Definition: CDSPSincFilterGen.h:32
double calcWindowGaussian()
Definition: CDSPSincFilterGen.h:254
double FracDelay
Fractional delay in the range [0; 1], used only in the generateFrac() function. Note that the FracDel...
Definition: CDSPSincFilterGen.h:60
EWindowFunctionType
Definition: CDSPSincFilterGen.h:74
@ wftKaiser
Kaiser window function. Requires the "Beta" parameter. The "Power" parameter is optional.
Definition: CDSPSincFilterGen.h:77
@ wftCosine
Generalized cosine window function. No parameters required. The "Power" parameter is optional.
Definition: CDSPSincFilterGen.h:75
@ wftGaussian
Gaussian window function. Requires the "Sigma" parameter. The "Power" parameter is optional.
Definition: CDSPSincFilterGen.h:79
double calcWindowHamming()
Definition: CDSPSincFilterGen.h:199
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
void generateHilbert(double *op, CWindowFunc wfunc=&CDSPSincFilterGen ::calcWindowBlackman)
Definition: CDSPSincFilterGen.h:411
int fl2
Internal "half kernel length" value. This value can be used as filter's latency in samples (taps),...
Definition: CDSPSincFilterGen.h:42
void generateBand(double *op, CWindowFunc wfunc=&CDSPSincFilterGen ::calcWindowBlackman)
Definition: CDSPSincFilterGen.h:319
double GaussianSigmaFrac
Equals FracDelay / GaussianSigma.
Definition: CDSPSincFilterGen.h:582
double calcWindowBlackmanNuttall()
Definition: CDSPSincFilterGen.h:227
double KaiserBeta
Kaiser window function's "Beta" coefficient.
Definition: CDSPSincFilterGen.h:572
double Freq1
Required corner circular frequency 1 [0; pi]. Used only in the generateBand() function.
Definition: CDSPSincFilterGen.h:50
int KernelLen
Resulting length of the filter kernel, this variable is set after the call to one of the "init" funct...
Definition: CDSPSincFilterGen.h:40
double(CDSPSincFilterGen ::* CWindowFunc)()
Window calculation function pointer type.
Definition: CDSPSincFilterGen.h:83
double Len2i
= 1.0 / Len2, initialized and used by some window functions for optimization (should not be initializ...
Definition: CDSPSincFilterGen.h:37
double calcWindowKaiser()
Definition: CDSPSincFilterGen.h:237
double calcWindowBlackman()
Definition: CDSPSincFilterGen.h:208
void initWindow(const EWindowFunctionType WinType=wftCosine, const double *const Params=NULL, const bool UsePower=false)
Definition: CDSPSincFilterGen.h:99
double Freq2
Required corner circular frequency 2 [0; pi]. Used only in the generateBand() function....
Definition: CDSPSincFilterGen.h:52
double KaiserMul
Kaiser window function's divisor, inverse.
Definition: CDSPSincFilterGen.h:574
void initHilbert(const EWindowFunctionType WinType=wftCosine, const double *const Params=NULL, const bool UsePower=false)
Definition: CDSPSincFilterGen.h:149
double calcWindowNuttall()
Definition: CDSPSincFilterGen.h:217
double KaiserLen2Frac
Equals FracDelay / Len2.
Definition: CDSPSincFilterGen.h:575
void initBand(const EWindowFunctionType WinType=wftCosine, const double *const Params=NULL, const bool UsePower=false)
Definition: CDSPSincFilterGen.h:124
void generateWindow(double *op, CWindowFunc wfunc=&CDSPSincFilterGen ::calcWindowBlackman)
Definition: CDSPSincFilterGen.h:271
double Len2
Required half filter kernel's length in samples (can be a fractional value). Final physical kernel le...
Definition: CDSPSincFilterGen.h:34
double GaussianSigmaI
Gaussian window function's "Sigma" coefficient, inverse.
Definition: CDSPSincFilterGen.h:580
double calcWindowHann()
Definition: CDSPSincFilterGen.h:190
Sine signal generator class.
Definition: r8bbase.h:671
void init(const double si, const double ph)
Definition: r8bbase.h:716
double generate()
Definition: r8bbase.h:743