Flan
CDSPResampler.h
Go to the documentation of this file.
1 //$ nobt
2 //$ nocpp
3 
16 #ifndef R8B_CDSPRESAMPLER_INCLUDED
17 #define R8B_CDSPRESAMPLER_INCLUDED
18 
19 #include "CDSPHBDownsampler.h"
20 #include "CDSPHBUpsampler.h"
21 #include "CDSPBlockConvolver.h"
22 #include "CDSPFracInterpolator.h"
23 
24 namespace r8b {
25 
47 {
48 public:
115  CDSPResampler( const double SrcSampleRate, const double DstSampleRate,
116  const int aMaxInLen, const double ReqTransBand = 2.0,
117  const double ReqAtten = 206.91,
118  const EDSPFilterPhaseResponse ReqPhase = fprLinearPhase )
119  : StepCapacity( 0 )
120  , StepCount( 0 )
121  , MaxInLen( aMaxInLen )
122  , CurMaxOutLen( aMaxInLen )
123  , LatencyFrac( 0.0 )
124  {
125  R8BASSERT( SrcSampleRate > 0.0 );
126  R8BASSERT( DstSampleRate > 0.0 );
127  R8BASSERT( MaxInLen > 0 );
128 
129  R8BCONSOLE( "* CDSPResampler: src=%.1f dst=%.1f len=%i tb=%.1f "
130  "att=%.2f ph=%i\n", SrcSampleRate, DstSampleRate, aMaxInLen,
131  ReqTransBand, ReqAtten, (int) ReqPhase );
132 
133  if( SrcSampleRate == DstSampleRate )
134  {
135  return;
136  }
137 
138  TmpBufCapacities[ 0 ] = 0;
139  TmpBufCapacities[ 1 ] = 0;
140  CurTmpBuf = 0;
141 
142  // Try some common efficient ratios requiring only a single step.
143 
144  const int CommonRatioCount = 5;
145  const int CommonRatios[ CommonRatioCount ][ 2 ] = {
146  { 1, 2 },
147  { 1, 3 },
148  { 2, 3 },
149  { 3, 2 },
150  { 3, 4 }
151  };
152 
153  int i;
154 
155  for( i = 0; i < CommonRatioCount; i++ )
156  {
157  const int num = CommonRatios[ i ][ 0 ];
158  const int den = CommonRatios[ i ][ 1 ];
159 
160  if( SrcSampleRate * num == DstSampleRate * den )
161  {
162  addProcessor( new CDSPBlockConvolver(
164  1.0 / ( num > den ? num : den ), ReqTransBand,
165  ReqAtten, ReqPhase, num ), num, den, LatencyFrac ));
166 
167  createTmpBuffers();
168  return;
169  }
170  }
171 
172  // Try whole-number power-of-2 or 3*power-of-2 upsampling.
173 
174  for( i = 2; i <= 3; i++ )
175  {
176  bool WasFound = false;
177  int c = 0;
178 
179  while( true )
180  {
181  const double NewSR = SrcSampleRate * ( i << c );
182 
183  if( NewSR == DstSampleRate )
184  {
185  WasFound = true;
186  break;
187  }
188 
189  if( NewSR > DstSampleRate )
190  {
191  break;
192  }
193 
194  c++;
195  }
196 
197  if( WasFound )
198  {
199  addProcessor( new CDSPBlockConvolver(
200  CDSPFIRFilterCache :: getLPFilter( 1.0 / i, ReqTransBand,
201  ReqAtten, ReqPhase, i ), i, 1, LatencyFrac ));
202 
203  const bool IsThird = ( i == 3 );
204 
205  for( i = 0; i < c; i++ )
206  {
207  addProcessor( new CDSPHBUpsampler( ReqAtten, i, IsThird,
208  LatencyFrac ));
209  }
210 
211  createTmpBuffers();
212  return;
213  }
214  }
215 
216  if( DstSampleRate * 2 > SrcSampleRate )
217  {
218  // Upsampling or fractional downsampling down to 2X.
219 
220  const double NormFreq = ( DstSampleRate > SrcSampleRate ? 0.5 :
221  0.5 * DstSampleRate / SrcSampleRate );
222 
223  addProcessor( new CDSPBlockConvolver(
224  CDSPFIRFilterCache :: getLPFilter( NormFreq, ReqTransBand,
225  ReqAtten, ReqPhase, 2.0 ), 2, 1, LatencyFrac ));
226 
227  // Try intermediate interpolated'd resampling with subsequent 2X
228  // or 3X upsampling.
229 
230  const double ThreshSampleRate = SrcSampleRate * 1.01;
231  int c = 0;
232  int div = 1;
233 
234  while( true )
235  {
236  const int ndiv = div * 2;
237 
238  if( DstSampleRate < ThreshSampleRate * ndiv )
239  {
240  break;
241  }
242 
243  div = ndiv;
244  c++;
245  }
246 
247  int c2 = 0;
248  int div2 = 1;
249 
250  while( true )
251  {
252  const int ndiv = div * ( c2 == 0 ? 3 : 2 );
253 
254  if( DstSampleRate < ThreshSampleRate * ndiv )
255  {
256  break;
257  }
258 
259  div2 = ndiv;
260  c2++;
261  }
262 
263  const double SrcSampleRate2 = SrcSampleRate * 2.0;
264  int tmp1;
265  int tmp2;
266 
267  if( c == 1 && getWholeStepping( SrcSampleRate2, DstSampleRate,
268  tmp1, tmp2 ))
269  {
270  // Do not use intermediate interpolation if whole stepping is
271  // available as it performs very fast.
272 
273  c = 0;
274  }
275 
276  if( c > 0 )
277  {
278  // Add steps using intermediate interpolation.
279 
280  int num;
281 
282  if( c2 > 0 && div2 > div )
283  {
284  div = div2;
285  c = c2;
286  num = 3;
287  }
288  else
289  {
290  num = 2;
291  }
292 
293  addProcessor( new CDSPFracInterpolator( SrcSampleRate2 * div,
294  DstSampleRate, ReqAtten, false, LatencyFrac ));
295 
296  const double tb = 100.0 * ( 1.0 - SrcSampleRate * div /
297  DstSampleRate ) / 1.75; // Divide TransBand by a constant
298  // that assures a linear response in the pass-band.
299 
300  addProcessor( new CDSPBlockConvolver(
301  CDSPFIRFilterCache :: getLPFilter( 1.0 / num, tb,
302  ReqAtten, ReqPhase, num ), num, 1, LatencyFrac ));
303 
304  for( i = 1; i < c; i++ )
305  {
306  addProcessor( new CDSPHBUpsampler( ReqAtten, i - 1,
307  ( num == 3 ), LatencyFrac ));
308  }
309  }
310  else
311  {
312  addProcessor( new CDSPFracInterpolator( SrcSampleRate2,
313  DstSampleRate, ReqAtten, false, LatencyFrac ));
314  }
315 
316  createTmpBuffers();
317  return;
318  }
319 
320  // Use downsampling steps, including power-of-2 downsampling.
321 
322  double CheckSR = DstSampleRate * 4.0;
323  int c = 0;
324  double FinGain = 1.0;
325 
326  while( CheckSR <= SrcSampleRate )
327  {
328  c++;
329  CheckSR *= 2.0;
330  FinGain *= 0.5;
331  }
332 
333  const int SrcSRDiv = ( 1 << c );
334  int downf;
335  double NormFreq = 0.5;
336  bool UseInterp = true;
337  bool IsThird = false;
338 
339  for( downf = 2; downf <= 3; downf++ )
340  {
341  if( DstSampleRate * SrcSRDiv * downf == SrcSampleRate )
342  {
343  NormFreq = 1.0 / downf;
344  UseInterp = false;
345  IsThird = ( downf == 3 );
346  break;
347  }
348  }
349 
350  if( UseInterp )
351  {
352  downf = 1;
353  NormFreq = DstSampleRate * SrcSRDiv / SrcSampleRate;
354  IsThird = ( NormFreq * 3.0 <= 1.0 );
355  }
356 
357  for( i = 0; i < c; i++ )
358  {
359  // Use a fixed very relaxed 2X downsampling filters, that at
360  // the final stage only guarantees stop-band between 0.75 and
361  // pi. 0.5-0.75 range will be aliased to 0.25-0.5 range which
362  // will then be filtered out by the final filter.
363 
364  addProcessor( new CDSPHBDownsampler( ReqAtten, c - 1 - i, IsThird,
365  LatencyFrac ));
366  }
367 
368  addProcessor( new CDSPBlockConvolver(
369  CDSPFIRFilterCache :: getLPFilter( NormFreq, ReqTransBand,
370  ReqAtten, ReqPhase, FinGain ), 1, downf, LatencyFrac ));
371 
372  if( UseInterp )
373  {
374  addProcessor( new CDSPFracInterpolator( SrcSampleRate,
375  DstSampleRate * SrcSRDiv, ReqAtten, IsThird, LatencyFrac ));
376  }
377 
378  createTmpBuffers();
379  }
380 
381  virtual ~CDSPResampler()
382  {
383  int i;
384 
385  for( i = 0; i < StepCount; i++ )
386  {
387  delete Steps[ i ];
388  }
389  }
390 
391  virtual int getLatency() const
392  {
393  return( 0 );
394  }
395 
396  virtual double getLatencyFrac() const
397  {
398  return( LatencyFrac );
399  }
400 
407  virtual int getMaxOutLen( const int/* MaxInLen */ ) const
408  {
409  return( CurMaxOutLen );
410  }
411 
424  virtual void clear()
425  {
426  int i;
427 
428  for( i = 0; i < StepCount; i++ )
429  {
430  Steps[ i ] -> clear();
431  }
432  }
433 
462  virtual int process( double* ip0, int l, double*& op0 )
463  {
464  R8BASSERT( l >= 0 );
465 
466  double* ip = ip0;
467  int i;
468 
469  for( i = 0; i < StepCount; i++ )
470  {
471  double* op = TmpBufs[ i & 1 ];
472  l = Steps[ i ] -> process( ip, l, op );
473  ip = op;
474  }
475 
476  op0 = ip;
477  return( l );
478  }
479 
493  template< class Tin, class Tout >
494  void oneshot( const Tin* ip, int iplen, Tout* op, int oplen )
495  {
496  CFixedBuffer< double > Buf( MaxInLen );
497  bool IsZero = false;
498 
499  while( oplen > 0 )
500  {
501  int rc;
502  double* p;
503  int i;
504 
505  if( iplen == 0 )
506  {
507  rc = MaxInLen;
508  p = &Buf[ 0 ];
509 
510  if( !IsZero )
511  {
512  IsZero = true;
513  memset( p, 0, MaxInLen * sizeof( double ));
514  }
515  }
516  else
517  {
518  rc = min( iplen, MaxInLen );
519 
520  if( sizeof( Tin ) == sizeof( double ))
521  {
522  p = (double*) ip;
523  }
524  else
525  {
526  p = &Buf[ 0 ];
527 
528  for( i = 0; i < rc; i++ )
529  {
530  p[ i ] = ip[ i ];
531  }
532  }
533 
534  ip += rc;
535  iplen -= rc;
536  }
537 
538  double* op0;
539  int wc = process( p, rc, op0 );
540  wc = min( oplen, wc );
541 
542  for( i = 0; i < wc; i++ )
543  {
544  op[ i ] = (Tout) op0[ i ];
545  }
546 
547  op += wc;
548  oplen -= wc;
549  }
550 
551  clear();
552  }
553 
564  {
565  int inc = 0;
566 
567  while( true )
568  {
569  double ins = 0.0;
570  double* op;
571 
572  if( process( &ins, 1, op ) > 0 )
573  {
574  clear();
575  return( inc );
576  }
577 
578  inc++;
579  }
580  }
581 
582 private:
584  int StepCapacity;
586  int StepCount;
588  int MaxInLen;
590  CFixedBuffer< double > TmpBufAll;
592  double* TmpBufs[ 2 ];
595  int TmpBufCapacities[ 2 ];
597  int CurTmpBuf;
600  int CurMaxOutLen;
602  double LatencyFrac;
604 
616  void addProcessor( CDSPProcessor* const Proc )
617  {
618  if( StepCount == StepCapacity )
619  {
620  // Reallocate and increase Steps array's capacity.
621 
622  const int NewCapacity = StepCapacity + 8;
623  Steps.realloc( StepCapacity, NewCapacity );
624  StepCapacity = NewCapacity;
625  }
626 
627  LatencyFrac = Proc -> getLatencyFrac();
628  CurMaxOutLen = Proc -> getMaxOutLen( CurMaxOutLen );
629 
630  if( CurMaxOutLen > TmpBufCapacities[ CurTmpBuf ])
631  {
632  TmpBufCapacities[ CurTmpBuf ] = CurMaxOutLen;
633  }
634 
635  CurTmpBuf ^= 1;
636 
637  Steps[ StepCount ] = Proc;
638  StepCount++;
639  }
640 
645  void createTmpBuffers()
646  {
647  const int ol = TmpBufCapacities[ 0 ] + TmpBufCapacities[ 1 ];
648 
649  if( ol > 0 )
650  {
651  TmpBufAll.alloc( ol );
652  TmpBufs[ 0 ] = &TmpBufAll[ 0 ];
653  TmpBufs[ 1 ] = &TmpBufAll[ TmpBufCapacities[ 0 ]];
654  }
655 
656  R8BCONSOLE( "* CDSPResampler: init done\n" );
657  }
658 };
659 
669 {
670 public:
682  CDSPResampler16( const double SrcSampleRate, const double DstSampleRate,
683  const int aMaxInLen, const double ReqTransBand = 2.0 )
684  : CDSPResampler( SrcSampleRate, DstSampleRate, aMaxInLen, ReqTransBand,
685  136.45, fprLinearPhase )
686  {
687  }
688 };
689 
700 {
701 public:
713  CDSPResampler16IR( const double SrcSampleRate, const double DstSampleRate,
714  const int aMaxInLen, const double ReqTransBand = 2.0 )
715  : CDSPResampler( SrcSampleRate, DstSampleRate, aMaxInLen, ReqTransBand,
716  109.56, fprLinearPhase )
717  {
718  }
719 };
720 
730 {
731 public:
743  CDSPResampler24( const double SrcSampleRate, const double DstSampleRate,
744  const int aMaxInLen, const double ReqTransBand = 2.0 )
745  : CDSPResampler( SrcSampleRate, DstSampleRate, aMaxInLen, ReqTransBand,
746  180.15, fprLinearPhase )
747  {
748  }
749 };
750 
751 } // namespace r8b
752 
753 #endif // R8B_CDSPRESAMPLER_INCLUDED
CDSPResampler(const double SrcSampleRate, const double DstSampleRate, const int aMaxInLen, const double ReqTransBand=2.0, const double ReqAtten=206.91, const EDSPFilterPhaseResponse ReqPhase=fprLinearPhase)
Constructor initalizes the resampler object.
Definition: CDSPResampler.h:115
#define R8BCONSOLE(...)
Console output macro, used to output various resampler status strings, including filter design parame...
Definition: r8bconf.h:85
Half-band downsampling convolver class.
virtual int getLatency() const
Definition: CDSPResampler.h:391
Half-band upsampling class.
Definition: CDSPHBUpsampler.h:30
The resampler class for 16-bit impulse response resampling.
Definition: CDSPResampler.h:699
CDSPResampler24(const double SrcSampleRate, const double DstSampleRate, const int aMaxInLen, const double ReqTransBand=2.0)
Constructor initializes the 24-bit resampler (including 32-bit floating point).
Definition: CDSPResampler.h:743
#define R8BASSERT(e)
Assertion macro used to check for certain run-time conditions.
Definition: r8bconf.h:72
Single-block overlap-save convolution processor class.
Linear-phase response.
Definition: CDSPFIRFilter.h:29
virtual int getMaxOutLen(const int) const
This function ignores the supplied parameter and returns the maximal output buffer length that depend...
Definition: CDSPResampler.h:407
The resampler class for 16-bit resampling.
Definition: CDSPResampler.h:668
The resampler class for 24-bit resampling.
Definition: CDSPResampler.h:729
Fractional delay interpolator and filter bank classes.
void oneshot(const Tin *ip, int iplen, Tout *op, int oplen)
Function performs resampling of an input sample buffer of the specified length in the "one-shot" mode...
Definition: CDSPResampler.h:494
Half-band downsampler class.
Definition: CDSPHBDownsampler.h:29
CDSPResampler16IR(const double SrcSampleRate, const double DstSampleRate, const int aMaxInLen, const double ReqTransBand=2.0)
Constructor initializes the 16-bit impulse response resampler.
Definition: CDSPResampler.h:713
T min(const T &v1, const T &v2)
Definition: r8bbase.h:1118
Single-block overlap-save convolution processing class.
Definition: CDSPBlockConvolver.h:38
CDSPResampler16(const double SrcSampleRate, const double DstSampleRate, const int aMaxInLen, const double ReqTransBand=2.0)
Constructor initializes the 16-bit resampler.
Definition: CDSPResampler.h:682
bool getWholeStepping(const double SSampleRate, const double DSampleRate, int &ResInStep, int &ResOutStep)
Function evaluates source and destination sample rate ratio and returns the required input and output...
Definition: CDSPFracInterpolator.h:573
virtual void clear()
Function clears (resets) the state of *this object and returns it to the state after construction...
Definition: CDSPResampler.h:424
virtual double getLatencyFrac() const
Definition: CDSPResampler.h:396
The master sample rate converter (resampler) class.
Definition: CDSPResampler.h:46
void realloc(const int PrevCapacity, const int NewCapacity)
Function reallocates memory so that the specified number of elements of type T can be stored in *this...
Definition: r8bbase.h:338
static CDSPFIRFilter & getLPFilter(const double ReqNormFreq, const double ReqTransBand, const double ReqAtten, const EDSPFilterPhaseResponse ReqPhase, const double ReqGain, const double *const AttenCorrs=NULL)
Function calculates or returns reference to a previously calculated (cached) low-pass FIR filter...
Definition: CDSPFIRFilter.h:602
The base virtual class for DSP processing algorithms.
Definition: CDSPProcessor.h:31
Fractional delay filter bank-based interpolator class.
Definition: CDSPFracInterpolator.h:619
EDSPFilterPhaseResponse
Enumeration of filter&#39;s phase responses.
Definition: CDSPFIRFilter.h:27
The "r8brain-free-src" library namespace.
Definition: CDSPBlockConvolver.h:21
int getInLenBeforeOutStart()
Function obtains overall input sample count required to produce first output sample.
Definition: CDSPResampler.h:563
virtual int process(double *ip0, int l, double *&op0)
Function performs sample rate conversion.
Definition: CDSPResampler.h:462
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
Half-band upsampling class.