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
53
54class CDSPResampler : public CDSPProcessor
55{
56public:
123
124 CDSPResampler( const double SrcSampleRate, const double DstSampleRate,
125 const int aMaxInLen, const double ReqTransBand = 2.0,
126 const double ReqAtten = 206.91,
127 const EDSPFilterPhaseResponse ReqPhase = fprLinearPhase )
128 : MaxInLen( aMaxInLen )
129 , CurMaxOutLen( aMaxInLen )
130 , LatencyFrac( 0.0 )
131 {
132 R8BASSERT( SrcSampleRate > 0.0 );
133 R8BASSERT( DstSampleRate > 0.0 );
134 R8BASSERT( MaxInLen > 0 );
135 R8BASSERT( ReqTransBand > 0.0 );
136 R8BASSERT( ReqAtten > 0.0 );
137
138 R8BCONSOLE( "* CDSPResampler: src=%.1f dst=%.1f len=%i tb=%.1f "
139 "att=%.2f ph=%i\n", SrcSampleRate, DstSampleRate, aMaxInLen,
140 ReqTransBand, ReqAtten, (int) ReqPhase );
141
142 if( SrcSampleRate == DstSampleRate )
143 {
144 return;
145 }
146
147 TmpBufCapacities[ 0 ] = 0;
148 TmpBufCapacities[ 1 ] = 0;
149 CurTmpBuf = 0;
150
151 // Try some common efficient ratios requiring only a single step.
152
153 const int CommonRatioCount = 5;
154 const int CommonRatios[ CommonRatioCount ][ 2 ] = {
155 { 1, 2 },
156 { 1, 3 },
157 { 2, 3 },
158 { 3, 2 },
159 { 3, 4 }
160 };
161
162 int i;
163
164 for( i = 0; i < CommonRatioCount; i++ )
165 {
166 const int num = CommonRatios[ i ][ 0 ];
167 const int den = CommonRatios[ i ][ 1 ];
168
169 if( SrcSampleRate * num == DstSampleRate * den )
170 {
171 addProcessor( new CDSPBlockConvolver(
172 CDSPFIRFilterCache :: getLPFilter(
173 1.0 / ( num > den ? num : den ), ReqTransBand,
174 ReqAtten, ReqPhase, num, den ), num, den, LatencyFrac ));
175
176 createTmpBuffers();
177 return;
178 }
179 }
180
181 // Try whole-number power-of-2 or 3*power-of-2 upsampling.
182
183 for( i = 2; i <= 3; i++ )
184 {
185 bool WasFound = false;
186 double sm = i;
187 int c = 0;
188
189 while( true )
190 {
191 const double NewSR = SrcSampleRate * sm;
192
193 if( NewSR == DstSampleRate )
194 {
195 WasFound = true;
196 break;
197 }
198
199 if( NewSR > DstSampleRate )
200 {
201 break;
202 }
203
204 sm *= 2.0;
205 c++;
206 }
207
208 if( WasFound )
209 {
210 addProcessor( new CDSPBlockConvolver(
211 CDSPFIRFilterCache :: getLPFilter( 1.0 / i, ReqTransBand,
212 ReqAtten, ReqPhase, i, 1 ), i, 1, LatencyFrac ));
213
214 const bool IsThirdFirst = ( i == 3 );
215
216 for( i = 0; i < c; i++ )
217 {
218 addProcessor( new CDSPHBUpsampler( ReqAtten, i,
219 ( IsThirdFirst || i > 1 ), LatencyFrac ));
220 }
221
222 createTmpBuffers();
223 return;
224 }
225 }
226
227 if( DstSampleRate * 2.0 > SrcSampleRate )
228 {
229 // Upsampling or fractional downsampling down to 2X.
230
231 const double NormFreq = ( DstSampleRate > SrcSampleRate ? 0.5 :
232 0.5 * DstSampleRate / SrcSampleRate );
233
234 addProcessor( new CDSPBlockConvolver(
235 CDSPFIRFilterCache :: getLPFilter( NormFreq, ReqTransBand,
236 ReqAtten, ReqPhase, 2.0, 1 ), 2, 1, LatencyFrac ));
237
238 // Try intermediate interpolated resampling with subsequent 2X
239 // or 3X upsampling.
240
241 const double tbw = 0.0175; // Intermediate filter's transition
242 // band extension coefficient.
243 const double ThreshSampleRate = SrcSampleRate /
244 ( 1.0 - tbw * ReqTransBand ); // Make sure intermediate
245 // filter's transition band is not steeper than ReqTransBand
246 // (this keeps the latency under control).
247
248 int c = 0;
249 double div = 1.0;
250
251 while( true )
252 {
253 const double ndiv = div * 2.0;
254
255 if( DstSampleRate < ThreshSampleRate * ndiv )
256 {
257 break;
258 }
259
260 div = ndiv;
261 c++;
262 }
263
264 const double SrcSampleRate2 = SrcSampleRate * 2.0;
265 int tmp1;
266 int tmp2;
267
268 if( c == 1 && getWholeStepping( SrcSampleRate2, DstSampleRate,
269 tmp1, tmp2 ))
270 {
271 // Do not use intermediate interpolation if whole stepping is
272 // available as it performs very fast.
273
274 c = 0;
275 }
276
277 if( c > 0 )
278 {
279 // Add steps using intermediate interpolation.
280
281 const int num = 2;
282
283 addProcessor( new CDSPFracInterpolator( SrcSampleRate2 * div,
284 DstSampleRate, ReqAtten, false, LatencyFrac ));
285
286 double tb = ( 1.0 - SrcSampleRate * div / DstSampleRate ) /
287 tbw; // Divide TransBand by a constant that assures a
288 // linear response in the pass-band.
289
290 if( tb > CDSPFIRFilter :: getLPMaxTransBand() )
291 {
292 tb = CDSPFIRFilter :: getLPMaxTransBand();
293 }
294
295 addProcessor( new CDSPBlockConvolver(
296 CDSPFIRFilterCache :: getLPFilter( 1.0 / num, tb,
297 ReqAtten, ReqPhase, num, 1 ), num, 1, LatencyFrac ));
298
299 for( i = 1; i < c; i++ )
300 {
301 addProcessor( new CDSPHBUpsampler( ReqAtten, i - 1,
302 ( i > 2 ), LatencyFrac ));
303 }
304 }
305 else
306 {
307 addProcessor( new CDSPFracInterpolator( SrcSampleRate2,
308 DstSampleRate, ReqAtten, false, LatencyFrac ));
309 }
310
311 createTmpBuffers();
312 return;
313 }
314
315 // Use downsampling steps, including power-of-2 downsampling.
316
317 double CheckSR = DstSampleRate * 4.0;
318 double SrcSRDiv = 1.0;
319 int c = 0;
320
321 while( CheckSR <= SrcSampleRate )
322 {
323 c++;
324 CheckSR *= 2.0;
325 SrcSRDiv *= 2.0;
326 }
327
328 const double FinGain = 1.0 / SrcSRDiv;
329
330 double NormFreq = 0.5;
331 bool UseInterp = true;
332 bool IsThirdFirst = false;
333 int downf;
334
335 for( downf = 2; downf <= 3; downf++ )
336 {
337 if( DstSampleRate * SrcSRDiv * downf == SrcSampleRate )
338 {
339 NormFreq = 1.0 / downf;
340 UseInterp = false;
341 IsThirdFirst = ( downf == 3 );
342 break;
343 }
344 }
345
346 if( UseInterp )
347 {
348 downf = 1;
349 NormFreq = DstSampleRate * SrcSRDiv / SrcSampleRate;
350 IsThirdFirst = ( NormFreq * 3.0 <= 1.0 );
351 }
352
353 for( i = 0; i < c; i++ )
354 {
355 // Use fixed, very relaxed 2X downsampling filters, that at the
356 // final stage only guarantee stop-band between 0.75 and 1.0 of
357 // Nyquist. 0.5-0.75 range will be aliased to 0.25-0.5 range which
358 // will then be filtered out by the final filter.
359
360 addProcessor( new CDSPHBDownsampler( ReqAtten, c - 1 - i,
361 ( IsThirdFirst || i < c - 2 ), LatencyFrac ));
362 }
363
364 addProcessor( new CDSPBlockConvolver(
365 CDSPFIRFilterCache :: getLPFilter( NormFreq, ReqTransBand,
366 ReqAtten, ReqPhase, FinGain, downf ), 1, downf, LatencyFrac ));
367
368 if( UseInterp )
369 {
370 addProcessor( new CDSPFracInterpolator( SrcSampleRate,
371 DstSampleRate * SrcSRDiv, ReqAtten, IsThirdFirst,
372 LatencyFrac ));
373 }
374
375 createTmpBuffers();
376 }
377
378 virtual int getInLenBeforeOutPos( int ReqOutPos ) const
379 {
380 R8BASSERT( ReqOutPos >= 0 );
381
382 if( Next != R8B_NULL )
383 {
384 ReqOutPos = Next -> getInLenBeforeOutPos( ReqOutPos );
385 }
386
387 if( StepFirst != R8B_NULL )
388 {
389 ReqOutPos = StepFirst -> getInLenBeforeOutPos( ReqOutPos );
390 }
391
392 return( ReqOutPos );
393 }
394
416
417 int getInLenBeforeOutStart( const int ReqOutPos = 0 )
418 {
419 R8BASSERT( ReqOutPos >= 0 );
420
421 int inc = 0;
422 int outc = 0;
423
424 while( true )
425 {
426 double ins = 0.0;
427 double* op;
428 outc += process( &ins, 1, op );
429
430 if( outc > ReqOutPos )
431 {
432 clear();
433 return( inc );
434 }
435
436 inc++;
437 }
438 }
439
449
450 int getInputRequiredForOutput( const int ReqOutSamples ) const
451 {
452 if( ReqOutSamples < 1 )
453 {
454 return( 0 );
455 }
456
457 return( getInLenBeforeOutPos( ReqOutSamples - 1 ) + 1 );
458 }
459
460 virtual int getLatency() const
461 {
462 return( 0 );
463 }
464
465 virtual double getLatencyFrac() const
466 {
467 return( LatencyFrac );
468 }
469
475
476 virtual int getMaxOutLen( const int/* MaxInLen */) const
477 {
478 return( CurMaxOutLen );
479 }
480
494
495 virtual void clear()
496 {
497 CDSPProcessor* ps = StepFirst;
498
499 while( ps != R8B_NULL )
500 {
501 ps -> clear();
502 ps = ps -> Next;
503 }
504 }
505
533
534 virtual int process( double* ip0, int l, double*& op0 )
535 {
536 R8BASSERT( l >= 0 && l <= MaxInLen );
537
538 double* ip = ip0;
539 int tp = 0;
540 CDSPProcessor* ps = StepFirst;
541
542 while( ps != R8B_NULL )
543 {
544 double* op = TmpBufs[ tp ];
545 l = ps -> process( ip, l, op );
546 ps = ps -> Next;
547 ip = op;
548 tp ^= 1;
549 }
550
551 op0 = ip;
552 return( l );
553 }
554
569
570 template< typename Tin, typename Tout >
571 void oneshot( Tin* ip, int iplen, Tout* op, int oplen )
572 {
573 CFixedBuffer< double > Buf( MaxInLen );
574 bool IsZero = false;
575
576 while( oplen > 0 )
577 {
578 int rc;
579 double* p;
580 int i;
581
582 if( iplen == 0 )
583 {
584 rc = MaxInLen;
585 p = &Buf[ 0 ];
586
587 if( !IsZero )
588 {
589 IsZero = true;
590 memset( p, 0, MaxInLen * sizeof( p[ 0 ]));
591 }
592 }
593 else
594 {
595 rc = min( iplen, MaxInLen );
596 p = getOneshotBuf( ip, Buf, rc );
597 ip += rc;
598 iplen -= rc;
599 }
600
601 double* op0;
602 int wc = process( p, rc, op0 );
603 wc = min( oplen, wc );
604
605 for( i = 0; i < wc; i++ )
606 {
607 op[ i ] = (Tout) op0[ i ];
608 }
609
610 op += wc;
611 oplen -= wc;
612 }
613
614 clear();
615 }
616
617private:
620 CDSPProcessor* StepLast;
622 int MaxInLen;
623 CFixedBuffer< double > TmpBufAll;
625 double* TmpBufs[ 2 ];
626 int TmpBufCapacities[ 2 ];
628 int CurTmpBuf;
629 int CurMaxOutLen;
630 double LatencyFrac;
633
641
642 void addProcessor( CDSPProcessor* const Proc )
643 {
644 if( StepFirst != R8B_NULL )
645 {
646 StepLast -> Next = Proc;
647 }
648 else
649 {
650 StepFirst = Proc;
651 }
652
653 StepLast = Proc;
654
655 LatencyFrac = Proc -> getLatencyFrac();
656 CurMaxOutLen = Proc -> getMaxOutLen( CurMaxOutLen );
657
658 if( CurMaxOutLen > TmpBufCapacities[ CurTmpBuf ])
659 {
660 TmpBufCapacities[ CurTmpBuf ] = CurMaxOutLen;
661 }
662
663 CurTmpBuf ^= 1;
664 }
665
669
670 void createTmpBuffers()
671 {
672 const int ol = TmpBufCapacities[ 0 ] + TmpBufCapacities[ 1 ];
673
674 if( ol > 0 )
675 {
676 TmpBufAll.alloc( ol );
677 TmpBufs[ 0 ] = &TmpBufAll[ 0 ];
678 TmpBufs[ 1 ] = &TmpBufAll[ TmpBufCapacities[ 0 ]];
679 }
680
681 R8BCONSOLE( "* CDSPResampler: init done\n" );
682 }
683
691
692 static double* getOneshotBuf( double* const ip, double* const, const int )
693 {
694 return( ip );
695 }
696
706
707 static double* getOneshotBuf( float* const ip, double* const Buf,
708 const int rc )
709 {
710 int i;
711
712 for( i = 0; i < rc; i++ )
713 {
714 Buf[ i ] = ip[ i ];
715 }
716
717 return( Buf );
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 R8B_NULL
The "null pointer" value, portable between C++11 and earlier C++ versions.
Definition r8bbase.h:101
#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:639
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:1257
Single-block overlap-save convolution processing class.
Definition CDSPBlockConvolver.h:40
Fractional delay filter bank-based interpolator class.
Definition CDSPFracInterpolator.h:687
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:36
virtual int getMaxOutLen(const int) const
This implementation ignores the supplied parameter and returns the maximal output buffer length that ...
Definition CDSPResampler.h:476
virtual double getLatencyFrac() const
Returns fractional latency, in samples, which is present in the output signal.
Definition CDSPResampler.h:465
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:417
void oneshot(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:571
virtual void clear()
Clears (resets) the state of this object and returns it to the state after construction.
Definition CDSPResampler.h:495
virtual int getLatency() const
Return the latency, in samples, which is present in the output signal.
Definition CDSPResampler.h:460
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:124
virtual int getInLenBeforeOutPos(int ReqOutPos) const
Returns the number of input samples required to advance to the specified output sample position (so t...
Definition CDSPResampler.h:378
virtual int process(double *ip0, int l, double *&op0)
Performs sample rate conversion.
Definition CDSPResampler.h:534
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:450
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
Pointer-to-object "keeper" class with automatic deletion.
Definition r8bbase.h:457
CDSPProcessor * Next
Definition r8bbase.h:652