Flan
CDSPRealFFT.h
Go to the documentation of this file.
1 //$ nobt
2 //$ nocpp
3 
17 #ifndef R8B_CDSPREALFFT_INCLUDED
18 #define R8B_CDSPREALFFT_INCLUDED
19 
20 #include "r8bbase.h"
21 
22 #if !R8B_IPP && !R8B_PFFFT
23  #include "fft4g.h"
24 #endif // !R8B_IPP && !R8B_PFFFT
25 
26 namespace r8b {
27 
47 class CDSPRealFFT : public R8B_BASECLASS
48 {
49  R8BNOCTOR( CDSPRealFFT );
50 
51  friend class CDSPRealFFTKeeper;
52 
53 public:
59  double getInvMulConst() const
60  {
61  return( InvMulConst );
62  }
63 
69  int getLenBits() const
70  {
71  return( LenBits );
72  }
73 
79  int getLen() const
80  {
81  return( Len );
82  }
83 
91  void forward( double* const p ) const
92  {
93  #if R8B_FLOATFFT
94 
95  float* const op = (float*) p;
96  int i;
97 
98  for( i = 0; i < Len; i++ )
99  {
100  op[ i ] = (float) p[ i ];
101  }
102 
103  #endif // R8B_FLOATFFT
104 
105  #if R8B_IPP
106 
107  ippsFFTFwd_RToPerm_64f( p, p, SPtr, WorkBuffer );
108 
109  #elif R8B_PFFFT
110 
111  pffft_transform_ordered( setup, op, op, work, PFFFT_FORWARD );
112 
113  #else // R8B_PFFFT
114 
115  ooura_fft :: rdft( Len, 1, p, wi.getPtr(), wd.getPtr() );
116 
117  #endif // R8B_IPP
118  }
119 
127  void inverse( double* const p ) const
128  {
129  #if R8B_IPP
130 
131  ippsFFTInv_PermToR_64f( p, p, SPtr, WorkBuffer );
132 
133  #elif R8B_PFFFT
134 
135  pffft_transform_ordered( setup, (float*) p, (float*) p, work,
136  PFFFT_BACKWARD );
137 
138  #else // R8B_PFFFT
139 
140  ooura_fft :: rdft( Len, -1, p, wi.getPtr(), wd.getPtr() );
141 
142  #endif // R8B_IPP
143 
144  #if R8B_FLOATFFT
145 
146  const float* const ip = (const float*) p;
147  int i;
148 
149  for( i = Len - 1; i >= 0; i-- )
150  {
151  p[ i ] = ip[ i ];
152  }
153 
154  #endif // R8B_FLOATFFT
155  }
156 
169  void multiplyBlocks( const double* const aip1, const double* const aip2,
170  double* const aop ) const
171  {
172  #if R8B_FLOATFFT
173 
174  const float* const ip1 = (const float*) aip1;
175  const float* const ip2 = (const float*) aip2;
176  float* const op = (float*) aop;
177 
178  #else // R8B_FLOATFFT
179 
180  const double* const ip1 = aip1;
181  const double* const ip2 = aip2;
182  double* const op = aop;
183 
184  #endif // R8B_FLOATFFT
185 
186  #if R8B_IPP
187 
188  ippsMulPerm_64f( (Ipp64f*) ip1, (Ipp64f*) ip2, (Ipp64f*) op, Len );
189 
190  #else // R8B_IPP
191 
192  op[ 0 ] = ip1[ 0 ] * ip2[ 0 ];
193  op[ 1 ] = ip1[ 1 ] * ip2[ 1 ];
194 
195  int i = 2;
196 
197  while( i < Len )
198  {
199  op[ i ] = ip1[ i ] * ip2[ i ] - ip1[ i + 1 ] * ip2[ i + 1 ];
200  op[ i + 1 ] = ip1[ i ] * ip2[ i + 1 ] + ip1[ i + 1 ] * ip2[ i ];
201  i += 2;
202  }
203 
204  #endif // R8B_IPP
205  }
206 
216  void multiplyBlocks( const double* const aip, double* const aop ) const
217  {
218  #if R8B_FLOATFFT
219 
220  const float* const ip = (const float*) aip;
221  float* const op = (float*) aop;
222  float t;
223 
224  #else // R8B_FLOATFFT
225 
226  const double* const ip = aip;
227  double* const op = aop;
228  double t;
229 
230  #endif // R8B_FLOATFFT
231 
232  #if R8B_IPP
233 
234  ippsMulPerm_64f( (Ipp64f*) op, (Ipp64f*) ip, (Ipp64f*) op, Len );
235 
236  #else // R8B_IPP
237 
238  op[ 0 ] *= ip[ 0 ];
239  op[ 1 ] *= ip[ 1 ];
240 
241  int i = 2;
242 
243  while( i < Len )
244  {
245  t = op[ i ] * ip[ i ] - op[ i + 1 ] * ip[ i + 1 ];
246  op[ i + 1 ] = op[ i ] * ip[ i + 1 ] + op[ i + 1 ] * ip[ i ];
247  op[ i ] = t;
248  i += 2;
249  }
250 
251  #endif // R8B_IPP
252  }
253 
266  void multiplyBlocksZ( const double* const aip, double* const aop ) const
267  {
268  #if R8B_FLOATFFT
269 
270  const float* const ip = (const float*) aip;
271  float* const op = (float*) aop;
272 
273  #else // R8B_FLOATFFT
274 
275  const double* const ip = aip;
276  double* const op = aop;
277 
278  #endif // R8B_FLOATFFT
279 
280  #if R8B_IPP
281 
282  ippsMul_64f_I( (const Ipp64f*) ip, (Ipp64f*) op, Len );
283 
284  #else // R8B_IPP
285 
286  int i;
287 
288  for( i = 0; i < Len; i++ )
289  {
290  op[ i ] *= ip[ i ];
291  }
292 
293  #endif // R8B_IPP
294  }
295 
303  void convertToZ( double* const ap ) const
304  {
305  #if R8B_FLOATFFT
306 
307  float* const p = (float*) ap;
308 
309  #else // R8B_FLOATFFT
310 
311  double* const p = ap;
312 
313  #endif // R8B_FLOATFFT
314 
315  int i = 2;
316 
317  while( i < Len )
318  {
319  p[ i + 1 ] = p[ i ];
320  i += 2;
321  }
322  }
323 
324 private:
325  int LenBits;
326  int Len;
328  double InvMulConst;
330  CDSPRealFFT* Next;
332 
334  #if R8B_IPP
335  IppsFFTSpec_R_64f* SPtr;
336  CFixedBuffer< unsigned char > SpecBuffer;
339  CFixedBuffer< unsigned char > WorkBuffer;
341  #elif R8B_PFFFT
343  PFFFT_Setup* setup;
344  CFixedBuffer< float > work;
346  #else // R8B_PFFFT
351  #endif // R8B_IPP
353 
359  class CObjKeeper
360  {
361  R8BNOCTOR( CObjKeeper );
362 
363  public:
364  CObjKeeper()
365  : Object( NULL )
366  {
367  }
368 
369  ~CObjKeeper()
370  {
371  delete Object;
372  }
373 
374  CObjKeeper& operator = ( CDSPRealFFT* const aObject )
375  {
376  Object = aObject;
377  return( *this );
378  }
379 
380  operator CDSPRealFFT* () const
381  {
382  return( Object );
383  }
384 
385  private:
386  CDSPRealFFT* Object;
387  };
389 
390  CDSPRealFFT()
391  {
392  }
393 
402  CDSPRealFFT( const int aLenBits )
403  : LenBits( aLenBits )
404  , Len( 1 << aLenBits )
405  #if R8B_IPP
406  , InvMulConst( 1.0 / Len )
407  #elif R8B_PFFFT
408  , InvMulConst( 1.0 / Len )
409  #else // R8B_PFFFT
410  , InvMulConst( 2.0 / Len )
411  #endif // R8B_IPP
412  {
413  #if R8B_IPP
414 
415  int SpecSize;
416  int SpecBufferSize;
417  int BufferSize;
418 
419  ippsFFTGetSize_R_64f( LenBits, IPP_FFT_NODIV_BY_ANY,
420  ippAlgHintFast, &SpecSize, &SpecBufferSize, &BufferSize );
421 
422  CFixedBuffer< unsigned char > InitBuffer( SpecBufferSize );
423  SpecBuffer.alloc( SpecSize );
424  WorkBuffer.alloc( BufferSize );
425 
426  ippsFFTInit_R_64f( &SPtr, LenBits, IPP_FFT_NODIV_BY_ANY,
427  ippAlgHintFast, SpecBuffer, InitBuffer );
428 
429  #elif R8B_PFFFT
430 
431  setup = pffft_new_setup( Len, PFFFT_REAL );
432  work.alloc( Len );
433 
434  #else // R8B_PFFFT
435 
436  wi.alloc( (int) ceil( 2.0 + sqrt( (double) ( Len >> 1 ))));
437  wi[ 0 ] = 0;
438  wd.alloc( Len >> 1 );
439 
440  #endif // R8B_IPP
441  }
442 
443  ~CDSPRealFFT()
444  {
445  #if R8B_PFFFT
446  pffft_destroy_setup( setup );
447  #endif // R8B_PFFFT
448 
449  delete Next;
450  }
451 };
452 
462 {
464 
465 public:
467  : Object( NULL )
468  {
469  }
470 
478  CDSPRealFFTKeeper( const int LenBits )
479  {
480  Object = acquire( LenBits );
481  }
482 
484  {
485  if( Object != NULL )
486  {
487  release( Object );
488  }
489  }
490 
495  const CDSPRealFFT* operator -> () const
496  {
497  R8BASSERT( Object != NULL );
498 
499  return( Object );
500  }
501 
510  void init( const int LenBits )
511  {
512  if( Object != NULL )
513  {
514  if( Object -> LenBits == LenBits )
515  {
516  return;
517  }
518 
519  release( Object );
520  }
521 
522  Object = acquire( LenBits );
523  }
524 
529  void reset()
530  {
531  if( Object != NULL )
532  {
533  release( Object );
534  Object = NULL;
535  }
536  }
537 
538 private:
539  CDSPRealFFT* Object;
540 
542  static CSyncObject StateSync;
543  static CDSPRealFFT :: CObjKeeper FFTObjects[];
545 
554  CDSPRealFFT* acquire( const int LenBits )
555  {
556  R8BASSERT( LenBits > 0 && LenBits <= 30 );
557 
558  R8BSYNC( StateSync );
559 
560  if( FFTObjects[ LenBits ] == NULL )
561  {
562  return( new CDSPRealFFT( LenBits ));
563  }
564 
565  CDSPRealFFT* ffto = FFTObjects[ LenBits ];
566  FFTObjects[ LenBits ] = ffto -> Next;
567 
568  return( ffto );
569  }
570 
577  void release( CDSPRealFFT* const ffto )
578  {
579  R8BSYNC( StateSync );
580 
581  ffto -> Next = FFTObjects[ ffto -> LenBits ];
582  FFTObjects[ ffto -> LenBits ] = ffto;
583  }
584 };
585 
609 inline void calcMinPhaseTransform( double* const Kernel, const int KernelLen,
610  const int LenMult = 2, const bool DoFinalMul = true,
611  double* const DCGroupDelay = NULL )
612 {
613  R8BASSERT( KernelLen > 0 );
614  R8BASSERT( LenMult >= 2 );
615 
616  const int LenBits = getBitOccupancy(( KernelLen * LenMult ) - 1 );
617  const int Len = 1 << LenBits;
618  const int Len2 = Len >> 1;
619  int i;
620 
621  CFixedBuffer< double > ip( Len );
622  CFixedBuffer< double > ip2( Len2 + 1 );
623 
624  memcpy( &ip[ 0 ], Kernel, KernelLen * sizeof( double ));
625  memset( &ip[ KernelLen ], 0, ( Len - KernelLen ) * sizeof( double ));
626 
627  CDSPRealFFTKeeper ffto( LenBits );
628  ffto -> forward( ip );
629 
630  // Create the "log |c|" spectrum while saving the original power spectrum
631  // in the "ip2" buffer.
632 
633  #if R8B_FLOATFFT
634  float* const aip = (float*) &ip[ 0 ];
635  float* const aip2 = (float*) &ip2[ 0 ];
636  const float nzbias = 1e-35;
637  #else // R8B_FLOATFFT
638  double* const aip = &ip[ 0 ];
639  double* const aip2 = &ip2[ 0 ];
640  const double nzbias = 1e-300;
641  #endif // R8B_FLOATFFT
642 
643  aip2[ 0 ] = aip[ 0 ];
644  aip[ 0 ] = log( fabs( aip[ 0 ]) + nzbias );
645  aip2[ Len2 ] = aip[ 1 ];
646  aip[ 1 ] = log( fabs( aip[ 1 ]) + nzbias );
647 
648  for( i = 1; i < Len2; i++ )
649  {
650  aip2[ i ] = sqrt( aip[ i * 2 ] * aip[ i * 2 ] +
651  aip[ i * 2 + 1 ] * aip[ i * 2 + 1 ]);
652 
653  aip[ i * 2 ] = log( aip2[ i ] + nzbias );
654  aip[ i * 2 + 1 ] = 0.0;
655  }
656 
657  // Convert to cepstrum and apply discrete Hilbert transform.
658 
659  ffto -> inverse( ip );
660 
661  const double m1 = ffto -> getInvMulConst();
662  const double m2 = -m1;
663 
664  ip[ 0 ] = 0.0;
665 
666  for( i = 1; i < Len2; i++ )
667  {
668  ip[ i ] *= m1;
669  }
670 
671  ip[ Len2 ] = 0.0;
672 
673  for( i = Len2 + 1; i < Len; i++ )
674  {
675  ip[ i ] *= m2;
676  }
677 
678  // Convert Hilbert-transformed cepstrum back to the "log |c|" spectrum and
679  // perform its exponentiation, multiplied by the power spectrum previously
680  // saved in the "ip2" buffer.
681 
682  ffto -> forward( ip );
683 
684  aip[ 0 ] = aip2[ 0 ];
685  aip[ 1 ] = aip2[ Len2 ];
686 
687  for( i = 1; i < Len2; i++ )
688  {
689  aip[ i * 2 + 0 ] = cos( aip[ i * 2 + 1 ]) * aip2[ i ];
690  aip[ i * 2 + 1 ] = sin( aip[ i * 2 + 1 ]) * aip2[ i ];
691  }
692 
693  ffto -> inverse( ip );
694 
695  if( DoFinalMul )
696  {
697  for( i = 0; i < KernelLen; i++ )
698  {
699  Kernel[ i ] = ip[ i ] * m1;
700  }
701  }
702  else
703  {
704  memcpy( &Kernel[ 0 ], &ip[ 0 ], KernelLen * sizeof( double ));
705  }
706 
707  if( DCGroupDelay != NULL )
708  {
709  double tmp;
710 
711  calcFIRFilterResponseAndGroupDelay( Kernel, KernelLen, 0.0,
712  tmp, tmp, *DCGroupDelay );
713  }
714 }
715 
716 } // namespace r8b
717 
718 #endif // VOX_CDSPREALFFT_INCLUDED
void init(const int LenBits)
Function acquires FFT object with the specified block length.
Definition: CDSPRealFFT.h:510
int getBitOccupancy(const int v)
Definition: r8bbase.h:775
double getInvMulConst() const
Definition: CDSPRealFFT.h:59
void convertToZ(double *const ap) const
Function converts the specified forward-transformed block into "zero-phase" form suitable for use wit...
Definition: CDSPRealFFT.h:303
#define R8BASSERT(e)
Assertion macro used to check for certain run-time conditions.
Definition: r8bconf.h:72
Real-valued FFT transform class.
Definition: CDSPRealFFT.h:47
Wrapper class for Takuya OOURA&#39;s FFT functions.
void forward(double *const p) const
Function performs in-place forward FFT.
Definition: CDSPRealFFT.h:91
void calcFIRFilterResponseAndGroupDelay(const double *const flt, const int fltlen, const double th, double &re, double &im, double &gd)
Function calculates frequency response and group delay of the specified FIR filter at the specified c...
Definition: r8bbase.h:882
#define R8BNOCTOR(ClassName)
A special macro that defines empty copy-constructor and copy operator with the "private:" prefix...
Definition: r8bbase.h:144
void multiplyBlocksZ(const double *const aip, double *const aop) const
Function multiplies two complex-valued data blocks in-place, considering that the "ip" block contains...
Definition: CDSPRealFFT.h:266
Multi-threaded synchronization object class.
Definition: r8bbase.h:526
The "base" inclusion file with basic classes and functions.
int getLenBits() const
Definition: CDSPRealFFT.h:69
void inverse(double *const p) const
Function performs in-place inverse FFT.
Definition: CDSPRealFFT.h:127
A "keeper" class for real-valued FFT transform objects.
Definition: CDSPRealFFT.h:461
int getLen() const
Definition: CDSPRealFFT.h:79
#define R8BSYNC(SyncObject)
The synchronization macro.
Definition: r8bbase.h:664
void multiplyBlocks(const double *const aip1, const double *const aip2, double *const aop) const
Function multiplies two complex-valued data blocks and places result in a new data block...
Definition: CDSPRealFFT.h:169
void reset()
Function releases a previously acquired FFT object.
Definition: CDSPRealFFT.h:529
Templated memory buffer class for element buffers of fixed capacity.
Definition: r8bbase.h:278
T * getPtr() const
Definition: r8bbase.h:378
#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:99
void calcMinPhaseTransform(double *const Kernel, const int KernelLen, const int LenMult=2, const bool DoFinalMul=true, double *const DCGroupDelay=NULL)
Function calculates the minimum-phase transform of the filter kernel, using a discrete Hilbert transf...
Definition: CDSPRealFFT.h:609
The "r8brain-free-src" library namespace.
Definition: CDSPBlockConvolver.h:21
void alloc(const int Capacity)
Function allocates memory so that the specified number of elements of type T can be stored in *this b...
Definition: r8bbase.h:318
void multiplyBlocks(const double *const aip, double *const aop) const
Function multiplies two complex-valued data blocks in-place.
Definition: CDSPRealFFT.h:216
CDSPRealFFTKeeper(const int LenBits)
Function acquires FFT object with the specified block length.
Definition: CDSPRealFFT.h:478