r8brain-free-src
High-quality pro audio sample rate converter library
 
Loading...
Searching...
No Matches
CDSPResampler.h
Go to the documentation of this file.
1//$ nobt
2//$ nocpp
3
16
17#ifndef R8B_CDSPRESAMPLER_INCLUDED
18#define R8B_CDSPRESAMPLER_INCLUDED
19
20#include "CDSPHBDownsampler.h"
21#include "CDSPHBUpsampler.h"
22#include "CDSPBlockConvolver.h"
24
25namespace r8b {
26
46
47class CDSPResampler : public CDSPProcessor
48{
49public:
116
117 CDSPResampler( const double SrcSampleRate, const double DstSampleRate,
118 const int aMaxInLen, const double ReqTransBand = 2.0,
119 const double ReqAtten = 206.91,
120 const EDSPFilterPhaseResponse ReqPhase = fprLinearPhase )
121 : StepCapacity( 0 )
122 , StepCount( 0 )
123 , MaxInLen( aMaxInLen )
124 , CurMaxOutLen( aMaxInLen )
125 , LatencyFrac( 0.0 )
126 {
127 R8BASSERT( SrcSampleRate > 0.0 );
128 R8BASSERT( DstSampleRate > 0.0 );
129 R8BASSERT( MaxInLen > 0 );
130
131 R8BCONSOLE( "* CDSPResampler: src=%.1f dst=%.1f len=%i tb=%.1f "
132 "att=%.2f ph=%i\n", SrcSampleRate, DstSampleRate, aMaxInLen,
133 ReqTransBand, ReqAtten, (int) ReqPhase );
134
135 if( SrcSampleRate == DstSampleRate )
136 {
137 return;
138 }
139
140 TmpBufCapacities[ 0 ] = 0;
141 TmpBufCapacities[ 1 ] = 0;
142 CurTmpBuf = 0;
143
144 // Try some common efficient ratios requiring only a single step.
145
146 const int CommonRatioCount = 5;
147 const int CommonRatios[ CommonRatioCount ][ 2 ] = {
148 { 1, 2 },
149 { 1, 3 },
150 { 2, 3 },
151 { 3, 2 },
152 { 3, 4 }
153 };
154
155 int i;
156
157 for( i = 0; i < CommonRatioCount; i++ )
158 {
159 const int num = CommonRatios[ i ][ 0 ];
160 const int den = CommonRatios[ i ][ 1 ];
161
162 if( SrcSampleRate * num == DstSampleRate * den )
163 {
164 addProcessor( new CDSPBlockConvolver(
165 CDSPFIRFilterCache :: getLPFilter(
166 1.0 / ( num > den ? num : den ), ReqTransBand,
167 ReqAtten, ReqPhase, num ), num, den, LatencyFrac ));
168
169 createTmpBuffers();
170 return;
171 }
172 }
173
174 // Try whole-number power-of-2 or 3*power-of-2 upsampling.
175
176 for( i = 2; i <= 3; i++ )
177 {
178 bool WasFound = false;
179 int c = 0;
180
181 while( true )
182 {
183 const double NewSR = SrcSampleRate * ( i << c );
184
185 if( NewSR == DstSampleRate )
186 {
187 WasFound = true;
188 break;
189 }
190
191 if( NewSR > DstSampleRate )
192 {
193 break;
194 }
195
196 c++;
197 }
198
199 if( WasFound )
200 {
201 addProcessor( new CDSPBlockConvolver(
202 CDSPFIRFilterCache :: getLPFilter( 1.0 / i, ReqTransBand,
203 ReqAtten, ReqPhase, i ), i, 1, LatencyFrac ));
204
205 const bool IsThird = ( i == 3 );
206
207 for( i = 0; i < c; i++ )
208 {
209 addProcessor( new CDSPHBUpsampler( ReqAtten, i, IsThird,
210 LatencyFrac ));
211 }
212
213 createTmpBuffers();
214 return;
215 }
216 }
217
218 if( DstSampleRate * 2.0 > SrcSampleRate )
219 {
220 // Upsampling or fractional downsampling down to 2X.
221
222 const double NormFreq = ( DstSampleRate > SrcSampleRate ? 0.5 :
223 0.5 * DstSampleRate / SrcSampleRate );
224
225 addProcessor( new CDSPBlockConvolver(
226 CDSPFIRFilterCache :: getLPFilter( NormFreq, ReqTransBand,
227 ReqAtten, ReqPhase, 2.0 ), 2, 1, LatencyFrac ));
228
229 // Try intermediate interpolated resampling with subsequent 2X
230 // or 3X upsampling.
231
232 const double tbw = 0.0175; // Intermediate filter's transition
233 // band extension coefficient.
234 const double ThreshSampleRate = SrcSampleRate /
235 ( 1.0 - tbw * ReqTransBand ); // Make sure intermediate
236 // filter's transition band is not steeper than ReqTransBand
237 // (this keeps the latency under control).
238
239 int c = 0;
240 int div = 1;
241
242 while( true )
243 {
244 const int ndiv = div * 2;
245
246 if( DstSampleRate < ThreshSampleRate * ndiv )
247 {
248 break;
249 }
250
251 div = ndiv;
252 c++;
253 }
254
255 int c2 = 0;
256 int div2 = 1;
257
258 while( true )
259 {
260 const int ndiv = div * ( c2 == 0 ? 3 : 2 );
261
262 if( DstSampleRate < ThreshSampleRate * ndiv )
263 {
264 break;
265 }
266
267 div2 = ndiv;
268 c2++;
269 }
270
271 const double SrcSampleRate2 = SrcSampleRate * 2.0;
272 int tmp1;
273 int tmp2;
274
275 if( c == 1 && getWholeStepping( SrcSampleRate2, DstSampleRate,
276 tmp1, tmp2 ))
277 {
278 // Do not use intermediate interpolation if whole stepping is
279 // available as it performs very fast.
280
281 c = 0;
282 }
283
284 if( c > 0 )
285 {
286 // Add steps using intermediate interpolation.
287
288 int num;
289
290 if( c2 > 0 && div2 > div )
291 {
292 div = div2;
293 c = c2;
294 num = 3;
295 }
296 else
297 {
298 num = 2;
299 }
300
301 addProcessor( new CDSPFracInterpolator( SrcSampleRate2 * div,
302 DstSampleRate, ReqAtten, false, LatencyFrac ));
303
304 double tb = ( 1.0 - SrcSampleRate * div / DstSampleRate ) /
305 tbw; // Divide TransBand by a constant that assures a
306 // linear response in the pass-band.
307
308 if( tb > CDSPFIRFilter :: getLPMaxTransBand() )
309 {
310 tb = CDSPFIRFilter :: getLPMaxTransBand();
311 }
312
313 addProcessor( new CDSPBlockConvolver(
314 CDSPFIRFilterCache :: getLPFilter( 1.0 / num, tb,
315 ReqAtten, ReqPhase, num ), num, 1, LatencyFrac ));
316
317 const bool IsThird = ( num == 3 );
318
319 for( i = 1; i < c; i++ )
320 {
321 addProcessor( new CDSPHBUpsampler( ReqAtten, i - 1,
322 IsThird, LatencyFrac ));
323 }
324 }
325 else
326 {
327 addProcessor( new CDSPFracInterpolator( SrcSampleRate2,
328 DstSampleRate, ReqAtten, false, LatencyFrac ));
329 }
330
331 createTmpBuffers();
332 return;
333 }
334
335 // Use downsampling steps, including power-of-2 downsampling.
336
337 double CheckSR = DstSampleRate * 4.0;
338 int c = 0;
339 double FinGain = 1.0;
340
341 while( CheckSR <= SrcSampleRate )
342 {
343 c++;
344 CheckSR *= 2.0;
345 FinGain *= 0.5;
346 }
347
348 const int SrcSRDiv = ( 1 << c );
349 int downf;
350 double NormFreq = 0.5;
351 bool UseInterp = true;
352 bool IsThird = false;
353
354 for( downf = 2; downf <= 3; downf++ )
355 {
356 if( DstSampleRate * SrcSRDiv * downf == SrcSampleRate )
357 {
358 NormFreq = 1.0 / downf;
359 UseInterp = false;
360 IsThird = ( downf == 3 );
361 break;
362 }
363 }
364
365 if( UseInterp )
366 {
367 downf = 1;
368 NormFreq = DstSampleRate * SrcSRDiv / SrcSampleRate;
369 IsThird = ( NormFreq * 3.0 <= 1.0 );
370 }
371
372 for( i = 0; i < c; i++ )
373 {
374 // Use fixed, very relaxed 2X downsampling filters, that at the
375 // final stage only guarantee stop-band between 0.75 and pi.
376 // 0.5-0.75 range will be aliased to 0.25-0.5 range which will
377 // then be filtered out by the final filter.
378
379 addProcessor( new CDSPHBDownsampler( ReqAtten, c - 1 - i, IsThird,
380 LatencyFrac ));
381 }
382
383 addProcessor( new CDSPBlockConvolver(
384 CDSPFIRFilterCache :: getLPFilter( NormFreq, ReqTransBand,
385 ReqAtten, ReqPhase, FinGain ), 1, downf, LatencyFrac ));
386
387 if( UseInterp )
388 {
389 addProcessor( new CDSPFracInterpolator( SrcSampleRate,
390 DstSampleRate * SrcSRDiv, ReqAtten, IsThird, LatencyFrac ));
391 }
392
393 createTmpBuffers();
394 }
395
396 virtual ~CDSPResampler()
397 {
398 int i;
399
400 for( i = 0; i < StepCount; i++ )
401 {
402 delete Steps[ i ];
403 }
404 }
405
406 virtual int getInLenBeforeOutPos( const int ReqOutPos ) const
407 {
408 R8BASSERT( ReqOutPos >= 0 );
409
410 int ReqInSamples = ReqOutPos;
411 int c = StepCount;
412
413 while( --c >= 0 )
414 {
415 ReqInSamples = Steps[ c ] -> getInLenBeforeOutPos( ReqInSamples );
416 }
417
418 return( ReqInSamples );
419 }
420
442
443 int getInLenBeforeOutStart( const int ReqOutPos = 0 )
444 {
445 R8BASSERT( ReqOutPos >= 0 );
446
447 int inc = 0;
448 int outc = 0;
449
450 while( true )
451 {
452 double ins = 0.0;
453 double* op;
454 outc += process( &ins, 1, op );
455
456 if( outc > ReqOutPos )
457 {
458 clear();
459 return( inc );
460 }
461
462 inc++;
463 }
464 }
465
475
476 int getInputRequiredForOutput( const int ReqOutSamples ) const
477 {
478 if( ReqOutSamples < 1 )
479 {
480 return( 0 );
481 }
482
483 return( getInLenBeforeOutPos( ReqOutSamples - 1 ) + 1 );
484 }
485
486 virtual int getLatency() const
487 {
488 return( 0 );
489 }
490
491 virtual double getLatencyFrac() const
492 {
493 return( LatencyFrac );
494 }
495
501
502 virtual int getMaxOutLen( const int/* MaxInLen */) const
503 {
504 return( CurMaxOutLen );
505 }
506
520
521 virtual void clear()
522 {
523 int i;
524
525 for( i = 0; i < StepCount; i++ )
526 {
527 Steps[ i ] -> clear();
528 }
529 }
530
558
559 virtual int process( double* ip0, int l, double*& op0 )
560 {
561 R8BASSERT( l >= 0 );
562
563 double* ip = ip0;
564 int i;
565
566 for( i = 0; i < StepCount; i++ )
567 {
568 double* op = TmpBufs[ i & 1 ];
569 l = Steps[ i ] -> process( ip, l, op );
570 ip = op;
571 }
572
573 op0 = ip;
574 return( l );
575 }
576
591
592 template< typename Tin, typename Tout >
593 void oneshot( const Tin* ip, int iplen, Tout* op, int oplen )
594 {
595 CFixedBuffer< double > Buf( MaxInLen );
596 bool IsZero = false;
597
598 while( oplen > 0 )
599 {
600 int rc;
601 double* p;
602 int i;
603
604 if( iplen == 0 )
605 {
606 rc = MaxInLen;
607 p = &Buf[ 0 ];
608
609 if( !IsZero )
610 {
611 IsZero = true;
612 memset( p, 0, MaxInLen * sizeof( p[ 0 ]));
613 }
614 }
615 else
616 {
617 rc = min( iplen, MaxInLen );
618
619 if( sizeof( Tin ) == sizeof( double ))
620 {
621 p = (double*) ip;
622 }
623 else
624 {
625 p = &Buf[ 0 ];
626
627 for( i = 0; i < rc; i++ )
628 {
629 p[ i ] = ip[ i ];
630 }
631 }
632
633 ip += rc;
634 iplen -= rc;
635 }
636
637 double* op0;
638 int wc = process( p, rc, op0 );
639 wc = min( oplen, wc );
640
641 for( i = 0; i < wc; i++ )
642 {
643 op[ i ] = (Tout) op0[ i ];
644 }
645
646 op += wc;
647 oplen -= wc;
648 }
649
650 clear();
651 }
652
653private:
655 int StepCapacity;
656 int StepCount;
657 int MaxInLen;
658 CFixedBuffer< double > TmpBufAll;
660 double* TmpBufs[ 2 ];
661 int TmpBufCapacities[ 2 ];
663 int CurTmpBuf;
664 int CurMaxOutLen;
665 double LatencyFrac;
668
676
677 void addProcessor( CDSPProcessor* const Proc )
678 {
679 if( StepCount == StepCapacity )
680 {
681 // Reallocate and increase Steps array's capacity.
682
683 const int NewCapacity = StepCapacity + 8;
684 Steps.realloc( StepCapacity, NewCapacity );
685 StepCapacity = NewCapacity;
686 }
687
688 LatencyFrac = Proc -> getLatencyFrac();
689 CurMaxOutLen = Proc -> getMaxOutLen( CurMaxOutLen );
690
691 if( CurMaxOutLen > TmpBufCapacities[ CurTmpBuf ])
692 {
693 TmpBufCapacities[ CurTmpBuf ] = CurMaxOutLen;
694 }
695
696 CurTmpBuf ^= 1;
697
698 Steps[ StepCount ] = Proc;
699 StepCount++;
700 }
701
705
706 void createTmpBuffers()
707 {
708 const int ol = TmpBufCapacities[ 0 ] + TmpBufCapacities[ 1 ];
709
710 if( ol > 0 )
711 {
712 TmpBufAll.alloc( ol );
713 TmpBufs[ 0 ] = &TmpBufAll[ 0 ];
714 TmpBufs[ 1 ] = &TmpBufAll[ TmpBufCapacities[ 0 ]];
715 }
716
717 R8BCONSOLE( "* CDSPResampler: init done\n" );
718 }
719};
720
728
730{
731public:
742
743 CDSPResampler16( const double SrcSampleRate, const double DstSampleRate,
744 const int aMaxInLen, const double ReqTransBand = 2.0 )
745 : CDSPResampler( SrcSampleRate, DstSampleRate, aMaxInLen, ReqTransBand,
746 136.45, fprLinearPhase )
747 {
748 }
749};
750
759
761{
762public:
773
774 CDSPResampler16IR( const double SrcSampleRate, const double DstSampleRate,
775 const int aMaxInLen, const double ReqTransBand = 2.0 )
776 : CDSPResampler( SrcSampleRate, DstSampleRate, aMaxInLen, ReqTransBand,
777 109.56, fprLinearPhase )
778 {
779 }
780};
781
789
791{
792public:
803
804 CDSPResampler24( const double SrcSampleRate, const double DstSampleRate,
805 const int aMaxInLen, const double ReqTransBand = 2.0 )
806 : CDSPResampler( SrcSampleRate, DstSampleRate, aMaxInLen, ReqTransBand,
807 180.15, fprLinearPhase )
808 {
809 }
810};
811
812} // namespace r8b
813
814#endif // R8B_CDSPRESAMPLER_INCLUDED
Single-block overlap-save convolution processor class.
Fractional delay interpolator and filter bank classes.
Half-band downsampling convolver class.
Half-band upsampling class.
#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 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
EDSPFilterPhaseResponse
Enumeration of filter's phase responses.
Definition CDSPFIRFilter.h:29
@ fprLinearPhase
Linear-phase response. Features a linear-phase, high-latency response, with the latency expressed as ...
Definition CDSPFIRFilter.h:30
T min(const T &v1, const T &v2)
Returns minimum of two values.
Definition r8bbase.h:1079
Single-block overlap-save convolution processing class.
Definition CDSPBlockConvolver.h:40
Fractional delay filter bank-based interpolator class.
Definition CDSPFracInterpolator.h:691
Half-band downsampler class.
Definition CDSPHBDownsampler.h:31
Half-band upsampling class.
Definition CDSPHBUpsampler.h:32
The base virtual class for DSP processing algorithms.
Definition CDSPProcessor.h:33
The master sample rate converter (resampler) class.
Definition CDSPResampler.h:48
virtual int getMaxOutLen(const int) const
This implementation ignores the supplied parameter and returns the maximal output buffer length that ...
Definition CDSPResampler.h:502
void oneshot(const Tin *ip, int iplen, Tout *op, int oplen)
Performs resampling of an input sample buffer of the specified length in the "one-shot" mode.
Definition CDSPResampler.h:593
virtual double getLatencyFrac() const
Returns fractional latency, in samples, which is present in the output signal.
Definition CDSPResampler.h:491
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 CDSPResampler.h:406
int getInLenBeforeOutStart(const int ReqOutPos=0)
Returns the number of input samples required to advance to the specified output sample position (so t...
Definition CDSPResampler.h:443
virtual void clear()
Clears (resets) the state of this object and returns it to the state after construction.
Definition CDSPResampler.h:521
virtual int getLatency() const
Return the latency, in samples, which is present in the output signal.
Definition CDSPResampler.h:486
CDSPResampler(const double SrcSampleRate, const double DstSampleRate, const int aMaxInLen, const double ReqTransBand=2.0, const double ReqAtten=206.91, const EDSPFilterPhaseResponse ReqPhase=fprLinearPhase)
Initalizes the resampler object.
Definition CDSPResampler.h:117
virtual int process(double *ip0, int l, double *&op0)
Performs sample rate conversion.
Definition CDSPResampler.h:559
int getInputRequiredForOutput(const int ReqOutSamples) const
Returns the number of input samples required to produce at least the specified number of output sampl...
Definition CDSPResampler.h:476
CDSPResampler16(const double SrcSampleRate, const double DstSampleRate, const int aMaxInLen, const double ReqTransBand=2.0)
Initializes the 16-bit resampler. See the r8b::CDSPResampler class for details.
Definition CDSPResampler.h:743
CDSPResampler16IR(const double SrcSampleRate, const double DstSampleRate, const int aMaxInLen, const double ReqTransBand=2.0)
Initializes the 16-bit impulse response resampler. See the r8b::CDSPResampler class for details.
Definition CDSPResampler.h:774
CDSPResampler24(const double SrcSampleRate, const double DstSampleRate, const int aMaxInLen, const double ReqTransBand=2.0)
Initializes the 24-bit resampler (including 32-bit floating point). See the r8b::CDSPResampler class ...
Definition CDSPResampler.h:804
void realloc(const int PrevCapacity, const int NewCapacity)
Reallocates memory so that the specified number of elements of type T can be stored in this buffer ob...
Definition r8bbase.h:340