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#ifndef R8B_CDSPRESAMPLER_INCLUDED
17#define R8B_CDSPRESAMPLER_INCLUDED
18
19#include "CDSPHBDownsampler.h"
20#include "CDSPHBUpsampler.h"
21#include "CDSPBlockConvolver.h"
23
24namespace r8b {
25
47{
48public:
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(
163 CDSPFIRFilterCache :: getLPFilter(
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.0 > 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 resampling with subsequent 2X
228 // or 3X upsampling.
229
230 const double tbw = 0.0175; // Intermediate filter's transition
231 // band extension coefficient.
232 const double ThreshSampleRate = SrcSampleRate /
233 ( 1.0 - tbw * ReqTransBand ); // Make sure intermediate
234 // filter's transition band is not steeper than ReqTransBand
235 // (this keeps the latency under control).
236
237 int c = 0;
238 int div = 1;
239
240 while( true )
241 {
242 const int ndiv = div * 2;
243
244 if( DstSampleRate < ThreshSampleRate * ndiv )
245 {
246 break;
247 }
248
249 div = ndiv;
250 c++;
251 }
252
253 int c2 = 0;
254 int div2 = 1;
255
256 while( true )
257 {
258 const int ndiv = div * ( c2 == 0 ? 3 : 2 );
259
260 if( DstSampleRate < ThreshSampleRate * ndiv )
261 {
262 break;
263 }
264
265 div2 = ndiv;
266 c2++;
267 }
268
269 const double SrcSampleRate2 = SrcSampleRate * 2.0;
270 int tmp1;
271 int tmp2;
272
273 if( c == 1 && getWholeStepping( SrcSampleRate2, DstSampleRate,
274 tmp1, tmp2 ))
275 {
276 // Do not use intermediate interpolation if whole stepping is
277 // available as it performs very fast.
278
279 c = 0;
280 }
281
282 if( c > 0 )
283 {
284 // Add steps using intermediate interpolation.
285
286 int num;
287
288 if( c2 > 0 && div2 > div )
289 {
290 div = div2;
291 c = c2;
292 num = 3;
293 }
294 else
295 {
296 num = 2;
297 }
298
299 addProcessor( new CDSPFracInterpolator( SrcSampleRate2 * div,
300 DstSampleRate, ReqAtten, false, LatencyFrac ));
301
302 double tb = ( 1.0 - SrcSampleRate * div / DstSampleRate ) /
303 tbw; // Divide TransBand by a constant that assures a
304 // linear response in the pass-band.
305
306 if( tb > CDSPFIRFilter :: getLPMaxTransBand() )
307 {
308 tb = CDSPFIRFilter :: getLPMaxTransBand();
309 }
310
311 addProcessor( new CDSPBlockConvolver(
312 CDSPFIRFilterCache :: getLPFilter( 1.0 / num, tb,
313 ReqAtten, ReqPhase, num ), num, 1, LatencyFrac ));
314
315 const bool IsThird = ( num == 3 );
316
317 for( i = 1; i < c; i++ )
318 {
319 addProcessor( new CDSPHBUpsampler( ReqAtten, i - 1,
320 IsThird, LatencyFrac ));
321 }
322 }
323 else
324 {
325 addProcessor( new CDSPFracInterpolator( SrcSampleRate2,
326 DstSampleRate, ReqAtten, false, LatencyFrac ));
327 }
328
329 createTmpBuffers();
330 return;
331 }
332
333 // Use downsampling steps, including power-of-2 downsampling.
334
335 double CheckSR = DstSampleRate * 4.0;
336 int c = 0;
337 double FinGain = 1.0;
338
339 while( CheckSR <= SrcSampleRate )
340 {
341 c++;
342 CheckSR *= 2.0;
343 FinGain *= 0.5;
344 }
345
346 const int SrcSRDiv = ( 1 << c );
347 int downf;
348 double NormFreq = 0.5;
349 bool UseInterp = true;
350 bool IsThird = false;
351
352 for( downf = 2; downf <= 3; downf++ )
353 {
354 if( DstSampleRate * SrcSRDiv * downf == SrcSampleRate )
355 {
356 NormFreq = 1.0 / downf;
357 UseInterp = false;
358 IsThird = ( downf == 3 );
359 break;
360 }
361 }
362
363 if( UseInterp )
364 {
365 downf = 1;
366 NormFreq = DstSampleRate * SrcSRDiv / SrcSampleRate;
367 IsThird = ( NormFreq * 3.0 <= 1.0 );
368 }
369
370 for( i = 0; i < c; i++ )
371 {
372 // Use fixed, very relaxed 2X downsampling filters, that at the
373 // final stage only guarantee stop-band between 0.75 and pi.
374 // 0.5-0.75 range will be aliased to 0.25-0.5 range which will
375 // then be filtered out by the final filter.
376
377 addProcessor( new CDSPHBDownsampler( ReqAtten, c - 1 - i, IsThird,
378 LatencyFrac ));
379 }
380
381 addProcessor( new CDSPBlockConvolver(
382 CDSPFIRFilterCache :: getLPFilter( NormFreq, ReqTransBand,
383 ReqAtten, ReqPhase, FinGain ), 1, downf, LatencyFrac ));
384
385 if( UseInterp )
386 {
387 addProcessor( new CDSPFracInterpolator( SrcSampleRate,
388 DstSampleRate * SrcSRDiv, ReqAtten, IsThird, LatencyFrac ));
389 }
390
391 createTmpBuffers();
392 }
393
394 virtual ~CDSPResampler()
395 {
396 int i;
397
398 for( i = 0; i < StepCount; i++ )
399 {
400 delete Steps[ i ];
401 }
402 }
403
404 virtual int getInLenBeforeOutPos( const int ReqOutPos ) const
405 {
406 R8BASSERT( ReqOutPos >= 0 );
407
408 int ReqInSamples = ReqOutPos;
409 int c = StepCount;
410
411 while( --c >= 0 )
412 {
413 ReqInSamples = Steps[ c ] -> getInLenBeforeOutPos( ReqInSamples );
414 }
415
416 return( ReqInSamples );
417 }
418
441 int getInLenBeforeOutStart( const int ReqOutPos = 0 )
442 {
443 R8BASSERT( ReqOutPos >= 0 );
444
445 int inc = 0;
446 int outc = 0;
447
448 while( true )
449 {
450 double ins = 0.0;
451 double* op;
452 outc += process( &ins, 1, op );
453
454 if( outc > ReqOutPos )
455 {
456 clear();
457 return( inc );
458 }
459
460 inc++;
461 }
462 }
463
474 int getInputRequiredForOutput( const int ReqOutSamples ) const
475 {
476 if( ReqOutSamples < 1 )
477 {
478 return( 0 );
479 }
480
481 return( getInLenBeforeOutPos( ReqOutSamples - 1 ) + 1 );
482 }
483
484 virtual int getLatency() const
485 {
486 return( 0 );
487 }
488
489 virtual double getLatencyFrac() const
490 {
491 return( LatencyFrac );
492 }
493
500 virtual int getMaxOutLen( const int/* MaxInLen */) const
501 {
502 return( CurMaxOutLen );
503 }
504
517 virtual void clear()
518 {
519 int i;
520
521 for( i = 0; i < StepCount; i++ )
522 {
523 Steps[ i ] -> clear();
524 }
525 }
526
555 virtual int process( double* ip0, int l, double*& op0 )
556 {
557 R8BASSERT( l >= 0 );
558
559 double* ip = ip0;
560 int i;
561
562 for( i = 0; i < StepCount; i++ )
563 {
564 double* op = TmpBufs[ i & 1 ];
565 l = Steps[ i ] -> process( ip, l, op );
566 ip = op;
567 }
568
569 op0 = ip;
570 return( l );
571 }
572
586 template< typename Tin, typename Tout >
587 void oneshot( const Tin* ip, int iplen, Tout* op, int oplen )
588 {
589 CFixedBuffer< double > Buf( MaxInLen );
590 bool IsZero = false;
591
592 while( oplen > 0 )
593 {
594 int rc;
595 double* p;
596 int i;
597
598 if( iplen == 0 )
599 {
600 rc = MaxInLen;
601 p = &Buf[ 0 ];
602
603 if( !IsZero )
604 {
605 IsZero = true;
606 memset( p, 0, MaxInLen * sizeof( p[ 0 ]));
607 }
608 }
609 else
610 {
611 rc = min( iplen, MaxInLen );
612
613 if( sizeof( Tin ) == sizeof( double ))
614 {
615 p = (double*) ip;
616 }
617 else
618 {
619 p = &Buf[ 0 ];
620
621 for( i = 0; i < rc; i++ )
622 {
623 p[ i ] = ip[ i ];
624 }
625 }
626
627 ip += rc;
628 iplen -= rc;
629 }
630
631 double* op0;
632 int wc = process( p, rc, op0 );
633 wc = min( oplen, wc );
634
635 for( i = 0; i < wc; i++ )
636 {
637 op[ i ] = (Tout) op0[ i ];
638 }
639
640 op += wc;
641 oplen -= wc;
642 }
643
644 clear();
645 }
646
647private:
649 int StepCapacity;
650 int StepCount;
651 int MaxInLen;
652 CFixedBuffer< double > TmpBufAll;
654 double* TmpBufs[ 2 ];
655 int TmpBufCapacities[ 2 ];
657 int CurTmpBuf;
658 int CurMaxOutLen;
659 double LatencyFrac;
662
671 void addProcessor( CDSPProcessor* const Proc )
672 {
673 if( StepCount == StepCapacity )
674 {
675 // Reallocate and increase Steps array's capacity.
676
677 const int NewCapacity = StepCapacity + 8;
678 Steps.realloc( StepCapacity, NewCapacity );
679 StepCapacity = NewCapacity;
680 }
681
682 LatencyFrac = Proc -> getLatencyFrac();
683 CurMaxOutLen = Proc -> getMaxOutLen( CurMaxOutLen );
684
685 if( CurMaxOutLen > TmpBufCapacities[ CurTmpBuf ])
686 {
687 TmpBufCapacities[ CurTmpBuf ] = CurMaxOutLen;
688 }
689
690 CurTmpBuf ^= 1;
691
692 Steps[ StepCount ] = Proc;
693 StepCount++;
694 }
695
700 void createTmpBuffers()
701 {
702 const int ol = TmpBufCapacities[ 0 ] + TmpBufCapacities[ 1 ];
703
704 if( ol > 0 )
705 {
706 TmpBufAll.alloc( ol );
707 TmpBufs[ 0 ] = &TmpBufAll[ 0 ];
708 TmpBufs[ 1 ] = &TmpBufAll[ TmpBufCapacities[ 0 ]];
709 }
710
711 R8BCONSOLE( "* CDSPResampler: init done\n" );
712 }
713};
714
724{
725public:
737 CDSPResampler16( const double SrcSampleRate, const double DstSampleRate,
738 const int aMaxInLen, const double ReqTransBand = 2.0 )
739 : CDSPResampler( SrcSampleRate, DstSampleRate, aMaxInLen, ReqTransBand,
740 136.45, fprLinearPhase )
741 {
742 }
743};
744
755{
756public:
768 CDSPResampler16IR( const double SrcSampleRate, const double DstSampleRate,
769 const int aMaxInLen, const double ReqTransBand = 2.0 )
770 : CDSPResampler( SrcSampleRate, DstSampleRate, aMaxInLen, ReqTransBand,
771 109.56, fprLinearPhase )
772 {
773 }
774};
775
785{
786public:
798 CDSPResampler24( const double SrcSampleRate, const double DstSampleRate,
799 const int aMaxInLen, const double ReqTransBand = 2.0 )
800 : CDSPResampler( SrcSampleRate, DstSampleRate, aMaxInLen, ReqTransBand,
801 180.15, fprLinearPhase )
802 {
803 }
804};
805
806} // namespace r8b
807
808#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)
Definition: r8bconf.h:27
#define R8BCONSOLE(...)
Definition: r8bconf.h:40
The "r8brain-free-src" library namespace.
Definition: CDSPBlockConvolver.h:21
bool getWholeStepping(const double SSampleRate, const double DSampleRate, int &ResInStep, int &ResOutStep)
Definition: CDSPFracInterpolator.h:642
EDSPFilterPhaseResponse
Definition: CDSPFIRFilter.h:28
@ fprLinearPhase
Linear-phase response. Features a linear-phase, high-latency response, with the latency expressed as ...
Definition: CDSPFIRFilter.h:29
T min(const T &v1, const T &v2)
Definition: r8bbase.h:1063
Single-block overlap-save convolution processing class.
Definition: CDSPBlockConvolver.h:39
Fractional delay filter bank-based interpolator class.
Definition: CDSPFracInterpolator.h:689
Half-band downsampler class.
Definition: CDSPHBDownsampler.h:30
Half-band upsampling class.
Definition: CDSPHBUpsampler.h:31
The base virtual class for DSP processing algorithms.
Definition: CDSPProcessor.h:32
The master sample rate converter (resampler) class.
Definition: CDSPResampler.h:47
virtual int getMaxOutLen(const int) const
Definition: CDSPResampler.h:500
void oneshot(const Tin *ip, int iplen, Tout *op, int oplen)
Definition: CDSPResampler.h:587
virtual double getLatencyFrac() const
Definition: CDSPResampler.h:489
virtual int getInLenBeforeOutPos(const int ReqOutPos) const
Definition: CDSPResampler.h:404
int getInLenBeforeOutStart(const int ReqOutPos=0)
Definition: CDSPResampler.h:441
virtual void clear()
Definition: CDSPResampler.h:517
virtual int getLatency() const
Definition: CDSPResampler.h:484
CDSPResampler(const double SrcSampleRate, const double DstSampleRate, const int aMaxInLen, const double ReqTransBand=2.0, const double ReqAtten=206.91, const EDSPFilterPhaseResponse ReqPhase=fprLinearPhase)
Definition: CDSPResampler.h:115
virtual int process(double *ip0, int l, double *&op0)
Definition: CDSPResampler.h:555
int getInputRequiredForOutput(const int ReqOutSamples) const
Definition: CDSPResampler.h:474
The resampler class for 16-bit resampling.
Definition: CDSPResampler.h:724
CDSPResampler16(const double SrcSampleRate, const double DstSampleRate, const int aMaxInLen, const double ReqTransBand=2.0)
Definition: CDSPResampler.h:737
The resampler class for 16-bit impulse response resampling.
Definition: CDSPResampler.h:755
CDSPResampler16IR(const double SrcSampleRate, const double DstSampleRate, const int aMaxInLen, const double ReqTransBand=2.0)
Definition: CDSPResampler.h:768
The resampler class for 24-bit resampling.
Definition: CDSPResampler.h:785
CDSPResampler24(const double SrcSampleRate, const double DstSampleRate, const int aMaxInLen, const double ReqTransBand=2.0)
Definition: CDSPResampler.h:798
void alloc(const int Capacity)
Definition: r8bbase.h:343
void realloc(const int PrevCapacity, const int NewCapacity)
Definition: r8bbase.h:363